README:再現方法とファイル構成

このオンライン補遺と再現コードは、論文「多党制は経済投票を弱めるのか?:政党の手がかりと経済の手がかりをめぐるコンジョイント実験」で報告する3つの実験の分析について、本文図、補遺図表、頑健性分析、無作為化・バランス診断、および支持政党別分析結果をまとめ、さらにそれらを再現するためのコードをまとめたものである。以下の手順で、入力データの読込みから最終的な図表・診断結果の整理までを一括して実行できる。

1. 再現に必要なファイル等

次の4ファイルを同じ作業ディレクトリに置いてもらう。データファイル名や保存場所を変更する場合は、このRmd冒頭の params を変更してもらえばよい。

ファイル 内容
partynum.csv 実験1の入力データ
conjoint_study2.csv 実験2の入力データ
conjoint_S3.csv 実験3の入力データ

2. 必要なRパッケージ

分析コードで使用する主要パッケージは以下のとおりである。

install.packages(c(
  "dplyr", "tidyr", "stringr", "purrr", "readr",
  "fixest", "tibble", "forcats", "ggplot2", "scales",
  "survival", "ggtext", "patchwork", "rmarkdown", "knitr"
))

3. 各種のデフォルト設定

冒頭の params で、入力ファイル、出力先、ブートストラップ回数を変更可能である。現在の主要なデフォルト値は次のとおりである。

パラメータ デフォルト 意味
output_root conjoint_replication_results 全出力を保存するルートディレクトリ
relative_cue_bootstrap_B 2000 主要な重要度・相対比重のブートストラップ反復数
support_bootstrap_B 500 支持政党別分析のブートストラップ反復数

4. 出力ファイル

分析結果はデフォルトで conjoint_replication_results/ 内に保存される設定になっている。主な構成は以下の通り。

  • main_text/:本文用の図と表
  • supplement/:実験別および実験横断の補遺図表(CSV、LaTeX、図)
  • diagnostics/:標本スクリーニング、割付バランス、プロフィール無作為化の診断
  • model_objects/:再利用可能なモデル・分析オブジェクト
  • logs/sessionInfo などの再現性情報

各分析の途中の経過作成される各種オブジェクトなどは _working/ に保存され、最終段階で上記のディレクトリに整理するように設定した。Rおよび各パッケージの実行環境は、分析完了後に sessionInfo として保存される設定となっている。

5. このオンライン補遺と再現コードの読み方

A節は本文・補遺の図表を生成する実行コード、B節以降は分析標本、推定量、無作為化・バランス診断、および各補足結果を、コードと対応させて確認するためのセクションである。画面上部の Show All Code / Hide All Code または右上の Code メニューから、コード全体の表示・非表示を切り替えられる。

A. 各図表の再現コード

A.1 共通コード

# 共通コード
options(stringsAsFactors = FALSE)

unified_output_root <- getOption(
  "conjoint.output_root",
  "conjoint_replication_results"
)

dir.create(
  unified_output_root,
  showWarnings = FALSE,
  recursive = TRUE
)

unified_config <- list(
  output_root = unified_output_root,

  cue_importance_metric_version = "v4_screening_autodetect",

  relative_cue_bootstrap_B = as.integer(
    getOption("conjoint.relative_cue_bootstrap_B", 2000L)
  ),
  relative_cue_bootstrap_seed = as.integer(
    getOption("conjoint.relative_cue_bootstrap_seed", 20260730L)
  ),
  relative_cue_bootstrap_progress_every = as.integer(
    getOption("conjoint.relative_cue_bootstrap_progress_every", 100L)
  ),
  rerun_relative_cue_bootstrap = isTRUE(
    getOption("conjoint.rerun_relative_cue_bootstrap", FALSE)
  ),

  min_support_total_n = as.integer(
    getOption("conjoint.min_support_total_n", 150L)
  ),
  min_support_cell_n = as.integer(
    getOption("conjoint.min_support_cell_n", 40L)
  ),
  support_bootstrap_B = as.integer(
    getOption("conjoint.support_bootstrap_B", 500L)
  ),
  support_bootstrap_seed = as.integer(
    getOption("conjoint.support_bootstrap_seed", 20260806L)
  ),
  rerun_support_bootstrap = isTRUE(
    getOption("conjoint.rerun_support_bootstrap", FALSE)
  ),

  study1 = list(
    data_file = getOption("conjoint.study1_data", "partynum.csv"),
    output_dir = file.path(unified_output_root, "_working", "study1")
  ),
  study2 = list(
    data_file = getOption("conjoint.study2_data", "conjoint_study2.csv"),
    output_dir = file.path(unified_output_root, "_working", "study2")
  ),
  study3 = list(
    data_file = getOption("conjoint.study3_data", "conjoint_S3.csv"),
    output_dir = file.path(unified_output_root, "_working", "study3")
  )
)

cat(
  "Unified conjoint replication pipeline\n",
  "Output root: ", unified_config$output_root, "\n",
  "Study 1 data: ", unified_config$study1$data_file, "\n",
  "Study 2 data: ", unified_config$study2$data_file, "\n",
  "Study 3 data: ", unified_config$study3$data_file, "\n",
  sep = ""
)


detect_final_consent_column <- function(
  raw,
  preferred_candidates = c("Q8.1", "Q9.1", "Q10.1"),
  study_label = "Study"
) {
  if (!is.data.frame(raw) || ncol(raw) == 0L) {
    stop("Check data")
  }

  preview_n <- min(12L, nrow(raw))

  normalize_preview <- function(x) {
    x <- as.character(x)
    x[is.na(x)] <- ""
    x <- gsub(" ", " ", x, fixed = TRUE)
    x <- gsub("[[:space:]]+", " ", x)
    trimws(x)
  }

  score_one <- function(column_name) {
    preview <- paste(
      normalize_preview(utils::head(raw[[column_name]], preview_n)),
      collapse = " "
    )

    score <- 0L

    if (grepl("最終意思確認", preview, fixed = TRUE)) {
      score <- score + 8L
    }
    if (grepl("こちらが調査の最後の画面", preview, fixed = TRUE) ||
        grepl("調査の最後の画面", preview, fixed = TRUE)) {
      score <- score + 6L
    }
    if (grepl("回答結果を送信する", preview, fixed = TRUE)) {
      score <- score + 8L
    }
    if (grepl("回答結果を送信しない", preview, fixed = TRUE) ||
        grepl("回答を送信しない", preview, fixed = TRUE)) {
      score <- score + 5L
    }
    if (grepl("本調査の主旨に同意", preview, fixed = TRUE) ||
        grepl("本調査の趣旨に同意", preview, fixed = TRUE)) {
      score <- score + 3L
    }
    if (column_name %in% preferred_candidates) {
      score <- score + 1L
    }

    score
  }

  candidate_table <- data.frame(
    column = names(raw),
    score = vapply(names(raw), score_one, integer(1)),
    stringsAsFactors = FALSE
  )

  candidate_table <- candidate_table[candidate_table$score > 0L, , drop = FALSE]

  if (nrow(candidate_table) == 0L) {
    existing_preferred <- preferred_candidates[
      preferred_candidates %in% names(raw)
    ]

    if (length(existing_preferred) == 1L) {
      message("Final consent: ", existing_preferred[[1]])
      return(existing_preferred[[1]])
    }

    likely_question_columns <- names(raw)[
      grepl("^Q[0-9]+(\\.[0-9]+)?(_[0-9]+)?$", names(raw))
    ]

    stop("Check final consent")
  }

  max_score <- max(candidate_table$score)
  best <- candidate_table$column[candidate_table$score == max_score]

  if (length(best) > 1L) {
    preferred_best <- preferred_candidates[
      preferred_candidates %in% best
    ]

    if (length(preferred_best) >= 1L) {
      best <- preferred_best[[1]]
    } else {
      stop("Check final consent")
    }
  }

  message("Final consent: ", best[[1]])


  best[[1]]
}

qualtrics_preview_text <- function(raw, column_name, preview_n = 12L) {
  if (!column_name %in% names(raw)) {
    return("")
  }

  x <- as.character(utils::head(raw[[column_name]], min(preview_n, nrow(raw))))
  x[is.na(x)] <- ""
  x <- gsub(" ", " ", x, fixed = TRUE)
  x <- gsub("[[:space:]]+", " ", x)
  trimws(paste(x, collapse = " "))
}

fullwidth_digit <- function(n) {
  substr("0123456789", n + 1L, n + 1L)
}

question_order_key <- function(x) {
  m <- regexec("^Q([0-9]+)\\.([0-9]+)", x)
  parts <- regmatches(x, m)

  vapply(
    parts,
    function(z) {
      if (length(z) < 3L) {
        return(Inf)
      }
      as.numeric(z[[2]]) * 1000 + as.numeric(z[[3]])
    },
    numeric(1)
  )
}

detect_attention_check_column <- function(
  raw,
  preferred_candidates = c("Q25.1_11", "Q25.1_10"),
  study_label = "Study"
) {
  metadata <- data.frame(
    column = names(raw),
    text = vapply(names(raw), function(v) qualtrics_preview_text(raw, v), character(1)),
    stringsAsFactors = FALSE
  )

  score <- integer(nrow(metadata))
  score <- score + ifelse(grepl("必ず", metadata$text, fixed = TRUE), 8L, 0L)
  score <- score + ifelse(grepl("選ん", metadata$text, fixed = TRUE), 5L, 0L)
  score <- score + ifelse(grepl("3|3", metadata$text), 4L, 0L)
  score <- score + ifelse(metadata$column %in% preferred_candidates, 1L, 0L)
  metadata$score <- score

  candidates <- metadata[
    grepl("必ず", metadata$text, fixed = TRUE) &
      grepl("選ん", metadata$text, fixed = TRUE) &
      grepl("3|3", metadata$text),
    ,
    drop = FALSE
  ]

  if (nrow(candidates) == 0L) {
    stop("Check attention item")
  }

  candidates <- candidates[order(-candidates$score), , drop = FALSE]
  best_score <- candidates$score[[1]]
  best <- candidates$column[candidates$score == best_score]

  if (length(best) > 1L) {
    preferred_best <- preferred_candidates[preferred_candidates %in% best]
    if (length(preferred_best) == 1L) {
      best <- preferred_best
    } else {
      stop("Check attention item")
    }
  }

  message("Attention item: ", best[[1]])
  best[[1]]
}

response_code_numeric <- function(x) {
  x <- as.character(x)
  x[is.na(x)] <- ""
  x <- gsub(" ", " ", x, fixed = TRUE)
  x <- trimws(gsub("[[:space:]]+", " ", x))

  exact <- grepl("^[0-9]+(?:\\.0+)?$", x, perl = TRUE)
  out <- rep(NA_real_, length(x))
  out[exact] <- suppressWarnings(as.numeric(x[exact]))

  trailing <- regexec("\\(([0-9]+)\\)\\s*$", x)
  trailing_parts <- regmatches(x, trailing)
  trailing_code <- vapply(
    trailing_parts,
    function(z) if (length(z) >= 2L) as.numeric(z[[2]]) else NA_real_,
    numeric(1)
  )
  out[is.na(out) & !is.na(trailing_code)] <- trailing_code[is.na(out) & !is.na(trailing_code)]

  first_num <- suppressWarnings(readr::parse_number(x))
  out[is.na(out)] <- first_num[is.na(out)]
  out
}

detect_attention_correct_code <- function(
  x,
  displayed_answer = 3L,
  recoded_answer = 6L,
  study_label = "Study"
) {
  code <- response_code_numeric(x)
  tab <- sort(table(code, useNA = "no"), decreasing = TRUE)

  n_display <- sum(code == displayed_answer, na.rm = TRUE)
  n_recode <- sum(code == recoded_answer, na.rm = TRUE)

  chosen <- if (n_recode > n_display) recoded_answer else displayed_answer
  n_nonmissing <- sum(!is.na(code))
  n_chosen <- sum(code == chosen, na.rm = TRUE)

  cat("\n", study_label, ":指示項目の回答コード分布\n", sep = "")
  print(utils::head(tab, 15L))
  cat(
    "採用する正答コード: ", chosen,
    "(表示上の正答は3)\n",
    sep = ""
  )

  if (n_nonmissing == 0L || n_chosen / n_nonmissing < 0.50) {
    stop("Check attention item")
  }

  as.character(chosen)
}

detect_conjoint_choice_map <- function(
  raw,
  party_numbers = 2:5,
  study_label = "Study"
) {
  metadata <- data.frame(
    column = names(raw),
    text = vapply(names(raw), function(v) qualtrics_preview_text(raw, v), character(1)),
    stringsAsFactors = FALSE
  )

  maps <- lapply(
    party_numbers,
    function(n_party) {
      digit_pattern <- paste0("(?:", n_party, "|", fullwidth_digit(n_party), ")\\s*つの選択肢")

      hit <- grepl("以下に", metadata$text, fixed = TRUE) &
        grepl("選択肢", metadata$text, fixed = TRUE) &
        grepl(digit_pattern, metadata$text, perl = TRUE) &
        grepl("衆議院", metadata$text, fixed = TRUE) &
        !grepl("提示された.*選択肢の数", metadata$text, perl = TRUE) &
        grepl("^Q[0-9]+\\.[0-9]+$", metadata$column)

      candidates <- metadata[hit, , drop = FALSE]
      candidates <- candidates[
        order(question_order_key(candidates$column)),
        ,
        drop = FALSE
      ]

      if (nrow(candidates) != 5L) {
        stop("Check choice columns")
      }

      data.frame(
        party_n = n_party,
        task = seq_len(5L),
        choice_var = candidates$column,
        stringsAsFactors = FALSE
      )
    }
  )

  out <- dplyr::bind_rows(maps)
  message("Choice columns: OK")
  print(out)
  out
}

detect_manipulation_map <- function(raw, choice_map, study_label = "Study") {
  metadata_text <- setNames(
    vapply(names(raw), function(v) qualtrics_preview_text(raw, v), character(1)),
    names(raw)
  )

  out <- lapply(
    sort(unique(choice_map$party_n)),
    function(n_party) {
      vars <- choice_map$choice_var[choice_map$party_n == n_party]
      roots <- sub("\\.[0-9]+$", "", vars)
      root <- names(sort(table(roots), decreasing = TRUE))[[1]]
      suffix <- suppressWarnings(as.integer(sub("^.*\\.", "", vars)))
      expected <- paste0(root, ".", max(suffix, na.rm = TRUE) + 1L)

      candidates <- names(metadata_text)[
        startsWith(names(metadata_text), paste0(root, ".")) &
          grepl("提示された", metadata_text, fixed = TRUE) &
          grepl("選択肢の数", metadata_text, fixed = TRUE)
      ]

      if (expected %in% candidates) {
        chosen <- expected
      } else if (length(candidates) == 1L) {
        chosen <- candidates[[1]]
      } else {
        stop("Check manipulation item")
      }

      data.frame(
        party_n = n_party,
        manipulation_var = chosen,
        correct_answer = as.character(n_party),
        stringsAsFactors = FALSE
      )
    }
  )

  out <- dplyr::bind_rows(out)
  message("Manipulation item: OK")
  print(out)
  out
}

parse_choice_position <- function(x) {
  x <- as.character(x)
  x[is.na(x)] <- ""
  x <- gsub(" ", " ", x, fixed = TRUE)
  x <- trimws(gsub("[[:space:]]+", " ", x))

  label_match <- regexec("(?:政党|状況|選択肢)\\s*([1-5])", x, perl = TRUE)
  label_parts <- regmatches(x, label_match)
  label_num <- vapply(
    label_parts,
    function(z) if (length(z) >= 2L) as.numeric(z[[2]]) else NA_real_,
    numeric(1)
  )

  exact <- grepl("^[1-5](?:\\.0+)?$", x, perl = TRUE)
  exact_num <- rep(NA_real_, length(x))
  exact_num[exact] <- suppressWarnings(as.numeric(x[exact]))

  trailing <- regexec("\\(([1-5])\\)\\s*$", x)
  trailing_parts <- regmatches(x, trailing)
  trailing_num <- vapply(
    trailing_parts,
    function(z) if (length(z) >= 2L) as.numeric(z[[2]]) else NA_real_,
    numeric(1)
  )

  out <- label_num
  out[is.na(out)] <- exact_num[is.na(out)]
  out[is.na(out)] <- trailing_num[is.na(out)]
  out
}

A.2 実験1:本文の図4・図5

# 本文コード
study1_env <- local({
required_packages <- c(
    "dplyr",
    "tidyr",
    "stringr",
    "purrr",
    "readr",
    "fixest",
    "tibble",
    "forcats",
    "ggplot2",
    "scales",
    "survival",
    "ggtext",
    "patchwork"
  )

  missing_packages <- required_packages[
    !vapply(required_packages, requireNamespace, logical(1), quietly = TRUE)
  ]

  if (length(missing_packages) > 0) {
    stop("No packages")
  }

  library(dplyr)
  library(tidyr)
  library(stringr)
  library(purrr)
  library(readr)
  library(fixest)
  library(tibble)
  library(forcats)
  library(ggplot2)
  library(scales)
  library(survival)
  library(patchwork)

  data_file <- unified_config$study1$data_file
  output_dir <- unified_config$study1$output_dir

  dir.create(output_dir, showWarnings = FALSE, recursive = TRUE)

  require_initial_consent <- TRUE
  require_final_consent <- TRUE
  initial_consent_var <- "Q1.1"
  final_consent_var <- "Q8.1"

  require_attention_check <- FALSE
  require_manipulation_check <- FALSE
  attention_check_var <- NA_character_
  attention_check_correct <- NA_character_

  require_all_five_tasks <- TRUE

  use_education_covariate <- FALSE

  relative_cue_bootstrap_B <- unified_config$relative_cue_bootstrap_B
  relative_cue_bootstrap_seed <- unified_config$relative_cue_bootstrap_seed + 1L
  relative_cue_bootstrap_progress_every <- unified_config$relative_cue_bootstrap_progress_every

  rerun_relative_cue_bootstrap <- unified_config$rerun_relative_cue_bootstrap


  norm_text <- function(x) {
    x %>%
      as.character() %>%
      str_squish() %>%
      str_replace_all("~", "~") %>%
      str_replace_all("〜", "~")
  }

  as_num <- function(x) {
    suppressWarnings(readr::parse_number(norm_text(x)))
  }

  is_response_code <- function(x, code) {
    x_norm <- norm_text(x)
    code_chr <- as.character(code)

    x_norm == code_chr |
      stringr::str_detect(x_norm, paste0("\\(", code_chr, "\\)$"))
  }

  first_existing <- function(dat, candidates) {
    out <- candidates[candidates %in% names(dat)]
    if (length(out) == 0) NA_character_ else out[1]
  }

  get_var <- function(dat, candidates) {
    v <- first_existing(dat, candidates)
    if (is.na(v)) {
      rep(NA_character_, nrow(dat))
    } else {
      dat[[v]]
    }
  }

  relevel_if_present <- function(x, ref) {
    x <- factor(x)
    if (ref %in% levels(x)) {
      relevel(x, ref = ref)
    } else {
      x
    }
  }

  factor_miss <- function(x, miss = "欠損・無回答") {
    x <- norm_text(x)
    x[is.na(x) | x == "" | x == "NA"] <- miss
    factor(x)
  }

  mean_impute <- function(x) {
    x <- as.numeric(x)
    miss <- as.integer(is.na(x))

    if (all(is.na(x))) {
      value <- x
    } else {
      value <- ifelse(is.na(x), mean(x, na.rm = TRUE), x)
    }

    list(value = value, miss = miss)
  }

  write_csv_safely <- function(x, filename) {
    readr::write_csv(x, file.path(output_dir, filename), na = "")
  }

  save_plot <- function(filename, plot, width, height, dpi = 300) {
    ggplot2::ggsave(
      filename = file.path(output_dir, filename),
      plot = plot,
      width = width,
      height = height,
      dpi = dpi
    )
  }


  if (!file.exists(data_file)) {
    stop("Check data")
  }

  raw <- readr::read_csv(
    data_file,
    col_types = cols(.default = col_character()),
    show_col_types = FALSE,
    name_repair = "minimal"
  )

  if (!"ResponseId" %in% names(raw)) {
    stop("Check data")
  }

  names(raw) <- names(raw) %>%
    str_replace("^F\\.(\\d+)\\.(\\d+)\\.(\\d+)$", "F-\\1-\\2-\\3") %>%
    str_replace("^F\\.(\\d+)\\.(\\d+)$", "F-\\1-\\2")

  if (
    require_final_consent &&
      (
        is.na(final_consent_var) ||
          !final_consent_var %in% names(raw)
      )
  ) {
    consent_question_pattern <- paste0(
      "回答結果を送信する|",
      "回答を送信しない|",
      "回答結果を送信しない|",
      "最終意思確認"
    )

    preview_n <- min(10L, nrow(raw))

    detected_final_consent_vars <- names(raw)[
      vapply(
        raw,
        function(column) {
          preview <- norm_text(
            utils::head(
              column,
              preview_n
            )
          )

          any(
            stringr::str_detect(
              preview,
              consent_question_pattern
            ),
            na.rm = TRUE
          )
        },
        logical(1)
      )
    ]

    if (length(detected_final_consent_vars) == 1L) {
      final_consent_var <- detected_final_consent_vars[[1]]

      message("Final consent: ", final_consent_var)
    } else if (length(detected_final_consent_vars) > 1L) {
      stop("Check final consent")
    } else {
      likely_question_columns <- names(raw)[
        stringr::str_detect(
          names(raw),
          "^Q[0-9]+(?:\\.[0-9]+)?$"
        )
      ]

      stop("Check final consent")
    }
  }

  df_header_removed <- raw %>%
    filter(
      !is.na(ResponseId),
      ResponseId != "",
      !str_detect(
        norm_text(ResponseId),
        "^(Response ID|回答ID)$|ImportId"
      )
    ) %>%
    mutate(ID = as.character(ResponseId))

  duplicate_ids <- df_header_removed %>%
    count(ID) %>%
    filter(n > 1)

  if (nrow(duplicate_ids) > 0) {
    print(duplicate_ids)
    stop("Check")
  }

  sample_flow <- tibble(
    stage = "Qualtrics質問文行・ImportId行を除外後",
    n = nrow(df_header_removed)
  )

  df <- df_header_removed

  if (require_initial_consent) {
    if (is.na(initial_consent_var) || !initial_consent_var %in% names(df)) {
      stop("Check initial consent")
    }
    df <- df %>%
      filter(
        is_response_code(.data[[initial_consent_var]], 1) |
          str_detect(
            norm_text(.data[[initial_consent_var]]),
            "趣旨に同意して.*協力する"
          )
      )
    sample_flow <- bind_rows(
      sample_flow,
      tibble(stage = "初回同意回答を保持", n = nrow(df))
    )
  }

  if (require_final_consent) {
    if (is.na(final_consent_var) || !final_consent_var %in% names(df)) {
      stop("Check final consent")
    }
    df <- df %>%
      filter(
        is_response_code(.data[[final_consent_var]], 1) |
          str_detect(
            norm_text(.data[[final_consent_var]]),
            "同意し.*回答結果を送信する"
          )
      )
    sample_flow <- bind_rows(
      sample_flow,
      tibble(stage = "最終同意回答を保持", n = nrow(df))
    )
  }

  print(sample_flow)
  write_csv_safely(sample_flow, "sample_flow_before_conjoint.csv")


  choice_map <- tribble(
    ~party_n, ~task, ~choice_var,
    2, 1, "Q240",
    2, 2, "Q253",
    2, 3, "Q254",
    2, 4, "Q255",
    2, 5, "Q256",

    3, 1, "Q235",
    3, 2, "Q241",
    3, 3, "Q242",
    3, 4, "Q243",
    3, 5, "Q244",

    4, 1, "Q238",
    4, 2, "Q245",
    4, 3, "Q246",
    4, 4, "Q247",
    4, 5, "Q248",

    5, 1, "Q239",
    5, 2, "Q249",
    5, 3, "Q250",
    5, 4, "Q251",
    5, 5, "Q252"
  )

  if (require_manipulation_check) {
    stop("Check")
  }


  level_to_attr_var <- function(x) {
    x <- norm_text(x)

    case_when(
      x %in% c("右派・保守的", "中道", "左派・革新的") ~
        "policy_position",

      x %in% c("与党", "野党") ~
        "government_status",

      str_detect(x, "GDP成長率") ~
        "gdp_growth",

      str_detect(x, "日経平均") ~
        "nikkei",

      x %in% c("10以下", "10~49", "50~99", "100~199", "200以上") ~
        "seats",

      str_detect(x, "CPI|物価") ~
        "cpi",

      str_detect(x, "失業率|雇用") ~
        "unemployment",

      TRUE ~ NA_character_
    )
  }

  required_attr_vars <- c(
    "policy_position",
    "government_status",
    "gdp_growth",
    "nikkei",
    "seats",
    "cpi",
    "unemployment"
  )

  allowed_levels <- list(
    policy_position = c("右派・保守的", "中道", "左派・革新的"),
    government_status = c("与党", "野党"),
    gdp_growth = c(
      "GDP成長率±0%",
      "GDP成長率プラス1%",
      "GDP成長率マイナス1%"
    ),
    nikkei = c(
      "日経平均前月同期比プラス1000円",
      "日経平均前月同期比マイナス1000円",
      "日経平均前月同期比変わらず"
    ),
    seats = c("10以下", "10~49", "50~99", "100~199", "200以上"),
    cpi = c(
      "CPI前期比±0ポイント",
      "CPI前期比プラス1ポイント",
      "CPI前期比マイナス1ポイント"
    ),
    unemployment = c(
      "失業率前期比±0%",
      "失業率前期比プラス1%",
      "失業率前期比マイナス1%"
    )
  )


  make_profile_long <- function(dat, n_party) {

    map_n <- choice_map %>%
      filter(party_n == n_party)

    qvars <- map_n$choice_var

    missing_q <- setdiff(qvars, names(dat))
    if (length(missing_q) > 0) {
      stop("Check choice columns")
    }

    dat_n <- dat %>%
      filter(
        if_any(
          all_of(qvars),
          ~ !is.na(.x) & norm_text(.x) != ""
        )
      )

    choice_long <- dat_n %>%
      select(ID, all_of(qvars)) %>%
      pivot_longer(
        cols = all_of(qvars),
        names_to = "choice_var",
        values_to = "choice_raw"
      ) %>%
      left_join(map_n, by = "choice_var") %>%
      mutate(choice = as_num(choice_raw)) %>%
      filter(!is.na(choice)) %>%
      select(ID, party_n, task, choice)

    invalid_choice <- choice_long %>%
      filter(choice < 1 | choice > n_party)

    if (nrow(invalid_choice) > 0) {
      print(invalid_choice)
      stop("Check choice values")
    }

    duplicate_choice <- choice_long %>%
      count(ID, task) %>%
      filter(n != 1)

    if (nrow(duplicate_choice) > 0) {
      print(duplicate_choice)
      stop("Check duplicate choices")
    }

    level_regex <- "^F-([1-5])-([1-5])-([1-7])$"
    level_cols <- names(dat_n)[str_detect(names(dat_n), level_regex)]

    if (length(level_cols) == 0) {
      stop("Check attributes")
    }

    level_long <- dat_n %>%
      select(ID, all_of(level_cols)) %>%
      pivot_longer(
        cols = all_of(level_cols),
        names_to = "fvar",
        values_to = "level"
      ) %>%
      extract(
        fvar,
        into = c("task", "profile", "attr_order"),
        regex = level_regex,
        convert = TRUE
      ) %>%
      mutate(level = norm_text(level)) %>%
      filter(
        task %in% 1:5,
        profile %in% 1:n_party,
        attr_order %in% 1:7,
        !is.na(level),
        level != ""
      ) %>%
      mutate(attr_var = level_to_attr_var(level))

    unknown_levels <- level_long %>%
      filter(is.na(attr_var)) %>%
      distinct(level)

    if (nrow(unknown_levels) > 0) {
      print(unknown_levels)
      stop("Check attributes")
    }

    profile_attribute_count <- level_long %>%
      count(ID, task, profile, name = "n_attribute_rows") %>%
      filter(n_attribute_rows != 7)

    if (nrow(profile_attribute_count) > 0) {
      print(head(profile_attribute_count, 50))
      stop("Check attributes")
    }

    duplicate_attribute <- level_long %>%
      count(ID, task, profile, attr_var) %>%
      filter(n != 1)

    if (nrow(duplicate_attribute) > 0) {
      print(head(duplicate_attribute, 50))
      stop("Check attributes")
    }

    profile_wide <- level_long %>%
      inner_join(choice_long, by = c("ID", "task")) %>%
      mutate(
        party_n = n_party,
        selected = as.integer(profile == choice),
        task_id = paste(ID, party_n, task, sep = "_"),
        profile_id = paste(ID, party_n, task, profile, sep = "_")
      ) %>%
      select(
        ID, party_n, task, profile, choice, selected,
        task_id, profile_id, attr_var, level
      ) %>%
      pivot_wider(
        names_from = attr_var,
        values_from = level,
        values_fn = list(level = ~ first(.x))
      )

    missing_attr <- setdiff(required_attr_vars, names(profile_wide))

    if (length(missing_attr) > 0) {
      stop("Check attributes")
    }

    profile_wide %>%
      select(
        ID, party_n, task, profile, choice, selected,
        task_id, profile_id,
        all_of(required_attr_vars)
      ) %>%
      arrange(ID, task, profile)
  }


  conjoint_2 <- make_profile_long(df, 2)
  conjoint_3 <- make_profile_long(df, 3)
  conjoint_4 <- make_profile_long(df, 4)
  conjoint_5 <- make_profile_long(df, 5)

  conjoint_all_unfiltered <- bind_rows(
    conjoint_2,
    conjoint_3,
    conjoint_4,
    conjoint_5
  )


  id_task_check <- conjoint_all_unfiltered %>%
    group_by(ID, party_n, task) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    group_by(ID, party_n) %>%
    summarise(
      n_tasks = n_distinct(task),
      all_tasks_ok = all(n_profiles == party_n & selected_sum == 1),
      .groups = "drop"
    )

  if (require_all_five_tasks) {
    valid_ids <- id_task_check %>%
      filter(n_tasks == 5, all_tasks_ok)
  } else {
    valid_ids <- id_task_check %>%
      filter(all_tasks_ok)
  }

  conjoint_all <- conjoint_all_unfiltered %>%
    semi_join(valid_ids, by = c("ID", "party_n"))

  n_by_party <- valid_ids %>%
    count(party_n, name = "n") %>%
    complete(party_n = 2:5, fill = list(n = 0)) %>%
    arrange(party_n)

  n_total <- valid_ids %>%
    summarise(n = n_distinct(ID)) %>%
    pull(n)

  figure_n_labels <- bind_rows(
    tibble(
      position = "全サンプル",
      label = paste0("全サンプル, n=", scales::comma(n_total))
    ),
    n_by_party %>%
      mutate(
        position = paste0(party_n, "政党選択"),
        label = paste0("n=", scales::comma(n))
      ) %>%
      select(position, label)
  )

  sample_flow <- bind_rows(
    sample_flow,
    tibble(
      stage = "完全な5課題をもつ分析対象者",
      n = n_total
    )
  )

  cat("\n分析対象者数\n")
  print(n_by_party)
  cat("全サンプル n=", n_total, "\n", sep = "")

  write_csv_safely(sample_flow, "sample_flow.csv")
  write_csv_safely(id_task_check, "id_task_check.csv")
  write_csv_safely(valid_ids, "valid_ids.csv")
  write_csv_safely(n_by_party, "n_by_party.csv")
  write_csv_safely(figure_n_labels, "figure_n_labels.csv")


  check_profile <- conjoint_all %>%
    group_by(party_n, ID, task, task_id) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    count(party_n, n_profiles, selected_sum)

  print(check_profile)
  stopifnot(all(check_profile$n_profiles == check_profile$party_n))
  stopifnot(all(check_profile$selected_sum == 1))

  allowed_df <- enframe(allowed_levels, name = "name", value = "value") %>%
    unnest(value)

  unexpected_values <- conjoint_all %>%
    select(all_of(required_attr_vars)) %>%
    pivot_longer(
      cols = everything(),
      names_to = "name",
      values_to = "value"
    ) %>%
    filter(!is.na(value), value != "") %>%
    distinct(name, value) %>%
    anti_join(allowed_df, by = c("name", "value"))

  print(unexpected_values)
  stopifnot(nrow(unexpected_values) == 0)

  observed_levels <- conjoint_all %>%
    select(all_of(required_attr_vars)) %>%
    pivot_longer(
      cols = everything(),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    distinct(attribute, level) %>%
    arrange(attribute, level)

  write_csv_safely(check_profile, "profile_expansion_check.csv")
  write_csv_safely(observed_levels, "observed_attribute_levels.csv")
  write_csv_safely(conjoint_all, "study1_profile_level_data.csv")


  if (require_attention_check) {
    if (
      is.na(attention_check_var) ||
        !attention_check_var %in% names(df) ||
        is.na(attention_check_correct)
    ) {
      stop("Check attention item")
    }
  }

  attention_summary <- tibble(
    note = "2023年元コードでは注意チェックの確定対応表を使用していないため、標準分析では集計を省略。"
  )

  manipulation_summary <- tibble(
    note = "2023年元コードでは政党数確認質問の確定対応表を使用していないため、標準分析では集計を省略。"
  )

  write_csv_safely(attention_summary, "attention_check_summary.csv")
  write_csv_safely(manipulation_summary, "party_number_check_summary.csv")


  conjoint_all_m <- conjoint_all %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),

      policy_position = factor(
        policy_position,
        levels = c("中道", "右派・保守的", "左派・革新的")
      ),

      government_status = factor(
        government_status,
        levels = c("野党", "与党")
      ),

      gdp_growth = factor(
        gdp_growth,
        levels = c(
          "GDP成長率±0%",
          "GDP成長率プラス1%",
          "GDP成長率マイナス1%"
        )
      ),

      nikkei = factor(
        nikkei,
        levels = c(
          "日経平均前月同期比変わらず",
          "日経平均前月同期比プラス1000円",
          "日経平均前月同期比マイナス1000円"
        )
      ),

      seats = factor(
        seats,
        levels = c("10以下", "10~49", "50~99", "100~199", "200以上")
      ),

      cpi = factor(
        cpi,
        levels = c(
          "CPI前期比±0ポイント",
          "CPI前期比プラス1ポイント",
          "CPI前期比マイナス1ポイント"
        )
      ),

      unemployment = factor(
        unemployment,
        levels = c(
          "失業率前期比±0%",
          "失業率前期比プラス1%",
          "失業率前期比マイナス1%"
        )
      ),

      party_n_f = factor(
        as.character(party_n),
        levels = c("2", "3", "4", "5")
      )
    )

  attr_terms <- c(
    "policy_position",
    "government_status",
    "gdp_growth",
    "nikkei",
    "seats",
    "cpi",
    "unemployment"
  )


  formula_nocov <- as.formula(
    paste("selected ~", paste(attr_terms, collapse = " + "))
  )

  run_amce_nocov <- function(dat) {
    feols(
      formula_nocov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_nocov <- conjoint_all_m %>%
    split(.$party_n) %>%
    map(run_amce_nocov)

  capture.output(
    etable(models_by_party_n_nocov),
    file = file.path(output_dir, "amce_nocov_models.txt")
  )


  m_interaction <- feols(
    selected ~
      party_n_f *
      (
        policy_position +
          government_status +
          gdp_growth +
          nikkei +
          seats +
          cpi +
          unemployment
      ),
    data = conjoint_all_m,
    vcov = ~ ID
  )

  capture.output(
    summary(m_interaction),
    file = file.path(output_dir, "amce_interaction_model.txt")
  )


  tidy_fixest <- function(model) {
    ct <- as.data.frame(fixest::coeftable(model))
    ct$term <- rownames(ct)

    ct %>%
      as_tibble() %>%
      rename(
        estimate = Estimate,
        std.error = `Std. Error`,
        statistic = `t value`,
        p.value = `Pr(>|t|)`
      ) %>%
      mutate(
        conf.low = estimate - 1.96 * std.error,
        conf.high = estimate + 1.96 * std.error
      ) %>%
      select(
        term, estimate, std.error, statistic, p.value,
        conf.low, conf.high
      )
  }

  term_labels <- tribble(
    ~term, ~attribute, ~cue_type, ~label, ~order,

    "government_status与党",
    "与党/野党", "政党の手がかり", "与党", 1,

    "policy_position右派・保守的",
    "政策位置", "政党の手がかり", "右派・保守的", 2,

    "policy_position左派・革新的",
    "政策位置", "政党の手がかり", "左派・革新的", 3,

    "seats10~49",
    "議席数", "政党の手がかり", "議席数:10~49", 4,

    "seats50~99",
    "議席数", "政党の手がかり", "議席数:50~99", 5,

    "seats100~199",
    "議席数", "政党の手がかり", "議席数:100~199", 6,

    "seats200以上",
    "議席数", "政党の手がかり", "議席数:200以上", 7,

    "gdp_growthGDP成長率プラス1%",
    "GDP成長率", "経済の手がかり", "GDP:プラス1%", 8,

    "gdp_growthGDP成長率マイナス1%",
    "GDP成長率", "経済の手がかり", "GDP:マイナス1%", 9,

    "nikkei日経平均前月同期比プラス1000円",
    "日経平均", "経済の手がかり", "日経平均:プラス1000円", 10,

    "nikkei日経平均前月同期比マイナス1000円",
    "日経平均", "経済の手がかり", "日経平均:マイナス1000円", 11,

    "cpiCPI前期比プラス1ポイント",
    "CPI", "経済の手がかり", "CPI:プラス1ポイント", 12,

    "cpiCPI前期比マイナス1ポイント",
    "CPI", "経済の手がかり", "CPI:マイナス1ポイント", 13,

    "unemployment失業率前期比プラス1%",
    "失業率", "経済の手がかり", "失業率:プラス1%", 14,

    "unemployment失業率前期比マイナス1%",
    "失業率", "経済の手がかり", "失業率:マイナス1%", 15
  )

  attribute_order <- c(
    "与党/野党",
    "政策位置",
    "議席数",
    "GDP成長率",
    "日経平均",
    "CPI",
    "失業率"
  )

  label_order <- term_labels %>%
    arrange(order) %>%
    pull(label)

  make_amce_plot_df <- function(models) {
    imap_dfr(
      models,
      ~ tidy_fixest(.x) %>%
        mutate(party_n = as.character(.y))
    ) %>%
      left_join(term_labels, by = "term") %>%
      filter(!is.na(attribute)) %>%
      mutate(
        estimate_pp = estimate * 100,
        conf.low_pp = conf.low * 100,
        conf.high_pp = conf.high * 100,
        party_n = factor(
          party_n,
          levels = c("2", "3", "4", "5"),
          labels = c("2政党", "3政党", "4政党", "5政党")
        ),
        attribute = factor(attribute, levels = attribute_order),
        label = factor(label, levels = rev(label_order))
      )
  }

  amce_plot_nocov <- make_amce_plot_df(models_by_party_n_nocov)
  write_csv_safely(amce_plot_nocov, "amce_nocov_coefficients.csv")

  interaction_plot_df <- tidy_fixest(m_interaction) %>%
    filter(str_detect(term, "party_n_f[345]")) %>%
    mutate(
      party_n_code = str_extract(term, "party_n_f[345]"),
      party_n = str_remove(party_n_code, "party_n_f"),
      base_term = term %>%
        str_remove("party_n_f[345]:") %>%
        str_remove(":party_n_f[345]")
    ) %>%
    left_join(term_labels, by = c("base_term" = "term")) %>%
    filter(!is.na(attribute)) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      party_n_label = factor(
        party_n,
        levels = c("3", "4", "5"),
        labels = c("3政党", "4政党", "5政党")
      ),
      attribute = factor(attribute, levels = attribute_order),
      label = factor(label, levels = rev(label_order))
    )

  write_csv_safely(interaction_plot_df, "amce_interaction_coefficients.csv")


  recode_female_study1 <- function(x) {
    x_chr <- norm_text(x)
    x_num <- as_num(x_chr)

    case_when(
      str_detect(x_chr, "女性") | x_num == 1 ~ 1L,
      str_detect(x_chr, "男性") | x_num == 2 ~ 0L,
      TRUE ~ NA_integer_
    )
  }

  recode_college_grad_study1 <- function(x) {
    x_chr <- norm_text(x)
    x_num <- as_num(x_chr)

    case_when(
      str_detect(x_chr, "4年制大学|4年制大学|大学院") |
        x_num %in% c(4, 5) ~ 1L,
      str_detect(x_chr, "小学校|高校|高等専門|短期大学|専修学校") |
        x_num %in% c(1, 2, 3) ~ 0L,
      TRUE ~ NA_integer_
    )
  }

  recode_party_support_study1 <- function(x) {
    x_chr <- norm_text(x)
    x_num <- as_num(x_chr)

    case_when(
      str_detect(x_chr, "自由民主|自民") | x_num == 1 ~ "自由民主党",
      str_detect(x_chr, "立憲民主") | x_num == 2 ~ "立憲民主党",
      str_detect(x_chr, "公明") | x_num == 3 ~ "公明党",
      str_detect(x_chr, "維新") | x_num == 4 ~ "日本維新の会",
      str_detect(x_chr, "共産") | x_num == 5 ~ "日本共産党",
      str_detect(x_chr, "国民民主") | x_num == 6 ~ "国民民主党",
      str_detect(x_chr, "社会民主|社民") | x_num == 7 ~ "社会民主党",
      str_detect(x_chr, "れいわ") | x_num == 8 ~ "れいわ新選組",
      str_detect(x_chr, "その他") | x_num == 11 ~ "その他",
      str_detect(x_chr, "支持する政党はない|支持政党なし") |
        x_num == 12 ~ "支持政党なし",
      str_detect(x_chr, "わからない") | x_num == 13 ~ "わからない",
      str_detect(x_chr, "答えない|こたえない") | x_num == 14 ~ "答えない",
      TRUE ~ NA_character_
    )
  }

  gender_raw <- get_var(
    df,
    c("Q2.1", "Q2_1", "Q2.1.", "性別", "gender", "Gender")
  )

  age_raw <- get_var(
    df,
    c("Q2.2", "Q2_2", "Q2.2.", "年齢", "age", "Age")
  )

  education_raw <- get_var(
    df,
    c(
      "Q2.3", "Q2_3", "Q2.3.",
      "学歴", "教育歴", "最終学歴", "education", "Education"
    )
  )

  party_support_raw <- get_var(
    df,
    c("Q2.4", "Q2_4", "Q2.4.", "政党支持", "支持政党", "party_support")
  )

  income_gross_raw <- get_var(
    df,
    c("Q3.1_1", "Q3.1.1", "Q3_1_1", "税引き前世帯年収", "income_gross")
  )

  income_net_raw <- get_var(
    df,
    c("Q3.1_2", "Q3.1.2", "Q3_1_2", "手取りの年収", "income_net")
  )

  covar_id <- df %>%
    transmute(
      ID = as.character(ResponseId),
      female = recode_female_study1(gender_raw),
      age_raw_num = as_num(age_raw),
      college_grad = recode_college_grad_study1(education_raw),
      party_support = recode_party_support_study1(party_support_raw),
      party_support_f = factor_miss(party_support),
      income_gross = as_num(income_gross_raw),
      income_net = as_num(income_net_raw),
      income_gross_log = log1p(income_gross),
      income_net_log = log1p(income_net)
    ) %>%
    mutate(
      age = case_when(
        !is.na(age_raw_num) & age_raw_num >= 18 & age_raw_num <= 80 ~
          age_raw_num,
        !is.na(age_raw_num) & age_raw_num >= 1 & age_raw_num <= 63 ~
          age_raw_num + 17,
        TRUE ~ NA_real_
      )
    ) %>%
    semi_join(valid_ids %>% select(ID), by = "ID") %>%
    distinct(ID, .keep_all = TRUE)

  age_imp_obj <- mean_impute(covar_id$age)
  income_gross_imp_obj <- mean_impute(covar_id$income_gross_log)

  covar_id <- covar_id %>%
    mutate(
      female_imp = if_else(is.na(female), 0L, female),
      female_miss = as.integer(is.na(female)),

      college_grad_imp = if_else(is.na(college_grad), 0L, college_grad),
      college_grad_miss = as.integer(is.na(college_grad)),

      age_imp = age_imp_obj$value,
      age_miss = age_imp_obj$miss,

      income_gross_log_imp = income_gross_imp_obj$value,
      income_gross_log_miss = income_gross_imp_obj$miss
    )

  covariate_missing_summary <- covar_id %>%
    summarise(
      n_ids = n_distinct(ID),
      female_missing = sum(is.na(female)),
      age_missing = sum(is.na(age)),
      college_grad_missing = sum(is.na(college_grad)),
      income_gross_missing = sum(is.na(income_gross_log)),
      party_support_missing = sum(is.na(party_support))
    )

  print(covariate_missing_summary)
  write_csv_safely(covar_id, "respondent_covariates.csv")
  write_csv_safely(covariate_missing_summary, "covariate_missing_summary.csv")


  conjoint_all_cov <- conjoint_all_m %>%
    left_join(covar_id, by = "ID")

  covariate_terms <- c(
    "female_imp",
    "female_miss",
    "age_imp",
    "age_miss",
    "income_gross_log_imp",
    "income_gross_log_miss",
    "party_support_f"
  )

  if (use_education_covariate) {
    covariate_terms <- c(
      covariate_terms,
      "college_grad_imp",
      "college_grad_miss"
    )
  }

  has_variation <- function(dat, v) {
    if (!v %in% names(dat)) return(FALSE)
    dplyr::n_distinct(dat[[v]], na.rm = TRUE) > 1
  }

  covariate_terms_use <- covariate_terms[
    map_lgl(covariate_terms, ~ has_variation(conjoint_all_cov, .x))
  ]

  formula_cov <- as.formula(
    paste(
      "selected ~",
      paste(c(attr_terms, covariate_terms_use), collapse = " + ")
    )
  )

  run_amce_cov <- function(dat) {
    feols(
      formula_cov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_cov <- conjoint_all_cov %>%
    split(.$party_n) %>%
    map(run_amce_cov)

  capture.output(
    etable(
      models_by_party_n_nocov,
      models_by_party_n_cov,
      headers = c(
        rep("共変量なし", length(models_by_party_n_nocov)),
        rep("共変量あり", length(models_by_party_n_cov))
      )
    ),
    file = file.path(output_dir, "amce_nocov_and_cov_models.txt")
  )

  amce_plot_cov <- make_amce_plot_df(models_by_party_n_cov)
  write_csv_safely(amce_plot_cov, "amce_cov_coefficients.csv")


  study_label <- "実験1(2023年)"

  term_labels_facet <- term_labels %>%
    mutate(
      attribute_facet = attribute
    )

  attribute_order_facet <- c(
    "与党/野党",
    "政策位置",
    "議席数",
    "GDP成長率",
    "日経平均",
    "CPI",
    "失業率"
  )

  make_amce_facet_df <- function(models) {
    imap_dfr(
      models,
      ~ tidy_fixest(.x) %>%
        mutate(party_n = as.character(.y))
    ) %>%
      left_join(term_labels_facet, by = "term") %>%
      filter(!is.na(attribute_facet)) %>%
      mutate(
        estimate_pp = estimate * 100,
        conf.low_pp = conf.low * 100,
        conf.high_pp = conf.high * 100,
        party_n = factor(
          party_n,
          levels = c("2", "3", "4", "5"),
          labels = c("2政党", "3政党", "4政党", "5政党")
        ),
        attribute_facet = factor(
          attribute_facet,
          levels = attribute_order_facet
        ),
        label = factor(
          label,
          levels = rev(label_order)
        )
      )
  }

  amce_plot_df_cov_facet <- make_amce_facet_df(models_by_party_n_cov)
  amce_plot_df_nocov_facet <- make_amce_facet_df(models_by_party_n_nocov)

  write_csv_safely(
    amce_plot_df_cov_facet,
    "amce_cov_facet_coefficients.csv"
  )

  write_csv_safely(
    amce_plot_df_nocov_facet,
    "amce_nocov_facet_coefficients.csv"
  )


  p_amce_cov_facet <- ggplot(
    amce_plot_df_cov_facet,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute_facet ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-12, 12, by = 2)
    ) +
    scale_shape_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = "Yu Gothic"
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_amce_cov_facet)

  save_plot(
    "amce_cov_facet_model.png",
    p_amce_cov_facet,
    width = 10.5,
    height = 8.5
  )

  p_amce_cov_main <- p_amce_cov_facet


  make_heatmap_df <- function(amce_plot_df) {
    heat_df <- amce_plot_df %>%
      mutate(
        abs_amce = abs(estimate_pp),
        cue_type_code = case_when(
          cue_type == "政党の手がかり" ~ "party",
          cue_type == "経済の手がかり" ~ "economy",
          TRUE ~ "other"
        )
      ) %>%
      group_by(party_n) %>%
      mutate(
        rank_within_party = min_rank(desc(abs_amce)),
        n_in_col = n(),
        rank_score = if_else(
          n_in_col == 1,
          1,
          1 - (rank_within_party - 1) / (n_in_col - 1)
        )
      ) %>%
      ungroup()

    row_order_df <- heat_df %>%
      group_by(label, cue_type_code) %>%
      summarise(
        mean_abs_amce = mean(abs_amce, na.rm = TRUE),
        .groups = "drop"
      ) %>%
      arrange(desc(mean_abs_amce))

    row_levels <- as.character(row_order_df$label)

    heat_df <- heat_df %>%
      mutate(
        label = factor(
          as.character(label),
          levels = rev(row_levels)
        )
      )

    label_color_map <- row_order_df %>%
      mutate(
        label_markdown = case_when(
          cue_type_code == "party" ~
            paste0(
              "<span style='color:#111111;'>",
              label,
              "</span>"
            ),
          cue_type_code == "economy" ~
            paste0(
              "<span style='color:#8A8A8A;'>",
              label,
              "</span>"
            ),
          TRUE ~ as.character(label)
        )
      )

    label_markdown_vec <- setNames(
      label_color_map$label_markdown,
      as.character(label_color_map$label)
    )

    list(
      heat_df = heat_df,
      label_markdown_vec = label_markdown_vec
    )
  }

  plot_amce_heatmap <- function(
      heat_df,
      label_markdown_vec,
      with_rank = TRUE,
      title_text = NULL) {

    if (with_rank) {
      heat_df <- heat_df %>%
        mutate(
          cell_label = paste0(
            sprintf("%.1f", estimate_pp),
            "\n(",
            rank_within_party,
            "位)"
          )
        )

      text_size <- 3.0
      lineheight <- 0.9
    } else {
      heat_df <- heat_df %>%
        mutate(
          cell_label = sprintf("%.1f", estimate_pp)
        )

      text_size <- 3.4
      lineheight <- 1.0
    }

    ggplot(
      heat_df,
      aes(
        x = party_n,
        y = label,
        fill = rank_score
      )
    ) +
      geom_tile(
        color = "white",
        linewidth = 0.7
      ) +
      geom_text(
        aes(label = cell_label),
        size = text_size,
        fontface = "bold",
        color = "black",
        lineheight = lineheight
      ) +
      scale_y_discrete(
        labels = label_markdown_vec
      ) +
      scale_fill_gradient(
        low = "grey95",
        high = "grey15",
        limits = c(0, 1),
        breaks = c(0, 0.25, 0.50, 0.75, 1.00),
        labels = c("低", "", "", "", "高"),
        name = "列内順位\n(濃いほど高位)"
      ) +
      labs(
        title = title_text,
        x = "政党数選択肢",
        y = NULL
      ) +
      theme_bw(base_size = 12) +
      theme(
        legend.position = "right",
        panel.grid = element_blank(),
        plot.title = element_text(face = "bold"),
        axis.text.x = element_text(size = 10),
        axis.text.y = ggtext::element_markdown(size = 9),
        axis.title.y = element_blank()
      )
  }

  heatmap_input <- make_heatmap_df(amce_plot_cov)

  p_heat_amce_mixed <- plot_amce_heatmap(
    heatmap_input$heat_df,
    heatmap_input$label_markdown_vec,
    with_rank = FALSE,
    title_text = NULL
  )

  print(p_heat_amce_mixed)

  save_plot(
    "amce_heatmap_mixed_rank_colored_labels.png",
    p_heat_amce_mixed,
    width = 8.8,
    height = 8.8
  )

  p_heat_amce_mixed_ranklabel <- plot_amce_heatmap(
    heatmap_input$heat_df,
    heatmap_input$label_markdown_vec,
    with_rank = TRUE,
    title_text = NULL
  )

  print(p_heat_amce_mixed_ranklabel)

  save_plot(
    "amce_heatmap_mixed_rank_colored_labels_withrank.png",
    p_heat_amce_mixed_ranklabel,
    width = 8.8,
    height = 8.8
  )

  p_heat_amce <- p_heat_amce_mixed
  p_heat_amce_rank <- p_heat_amce_mixed_ranklabel


  p_amce_facet_nocov <- ggplot(
    amce_plot_df_nocov_facet,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute_facet ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-12, 12, by = 2)
    ) +
    scale_shape_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(base_size = 12) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_amce_facet_nocov)

  save_plot(
    "amce_facet_nocov.png",
    p_amce_facet_nocov,
    width = 10.5,
    height = 9
  )

  p_amce_nocov_appendix <- p_amce_facet_nocov


  p_interaction <- ggplot(
    interaction_plot_df,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n_label,
      linetype = party_n_label,
      group = party_n_label
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-8, 8, by = 2)
    ) +
    scale_shape_manual(
      name = "2政党の場合との比較",
      values = c(
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "2政党の場合との比較",
      values = c(
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "2政党条件との差",
      y = NULL
    ) +
    theme_bw(base_size = 12) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 15
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_interaction)

  save_plot(
    "amce_interaction_difference_from_2party.png",
    p_interaction,
    width = 10.5,
    height = 9
  )


  conjoint_clogit <- conjoint_all_m %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),
      task_id = factor(task_id),
      policy_position = relevel_if_present(
        policy_position,
        "中道"
      ),
      government_status = relevel_if_present(
        government_status,
        "野党"
      ),
      gdp_growth = relevel_if_present(
        gdp_growth,
        "GDP成長率±0%"
      ),
      nikkei = relevel_if_present(
        nikkei,
        "日経平均前月同期比変わらず"
      ),
      seats = relevel_if_present(
        seats,
        "10以下"
      ),
      cpi = relevel_if_present(
        cpi,
        "CPI前期比±0ポイント"
      ),
      unemployment = relevel_if_present(
        unemployment,
        "失業率前期比±0%"
      )
    )

  formula_clogit_nocov <- as.formula(
    paste0(
      "selected ~ ",
      paste(attr_terms, collapse = " + "),
      " + strata(task_id) + cluster(ID)"
    )
  )

  run_clogit_nocov <- function(dat) {
    survival::clogit(
      formula_clogit_nocov,
      data = dat,
      method = "efron"
    )
  }

  models_clogit_nocov <- conjoint_clogit %>%
    split(.$party_n) %>%
    map(run_clogit_nocov)

  capture.output(
    lapply(models_clogit_nocov, summary),
    file = file.path(
      output_dir,
      "conditional_logit_models.txt"
    )
  )

  tidy_clogit <- function(model) {
    s <- summary(model)
    ct <- as.data.frame(s$coefficients)
    ct$term <- rownames(ct)

    se_col <- if ("robust se" %in% names(ct)) {
      "robust se"
    } else if ("se(coef)" %in% names(ct)) {
      "se(coef)"
    } else {
      stop("Check clogit")
    }

    p_col <- if ("Pr(>|z|)" %in% names(ct)) {
      "Pr(>|z|)"
    } else if ("Pr(>|t|)" %in% names(ct)) {
      "Pr(>|t|)"
    } else {
      NA_character_
    }

    ct %>%
      as_tibble() %>%
      transmute(
        term = term,
        estimate = coef,
        std.error = .data[[se_col]],
        p.value = if (!is.na(p_col)) {
          .data[[p_col]]
        } else {
          NA_real_
        },
        conf.low = estimate - 1.96 * std.error,
        conf.high = estimate + 1.96 * std.error,
        odds_ratio = exp(estimate),
        odds_ratio_low = exp(conf.low),
        odds_ratio_high = exp(conf.high)
      )
  }

  clogit_plot_df <- imap_dfr(
    models_clogit_nocov,
    ~ tidy_clogit(.x) %>%
      mutate(party_n = as.character(.y))
  ) %>%
    left_join(term_labels, by = "term") %>%
    filter(!is.na(attribute)) %>%
    mutate(
      party_n = factor(
        party_n,
        levels = c("2", "3", "4", "5"),
        labels = c("2政党", "3政党", "4政党", "5政党")
      ),
      label = factor(
        label,
        levels = rev(label_order)
      )
    )

  write_csv_safely(
    clogit_plot_df,
    "conditional_logit_coefficients.csv"
  )


  p_clogit_or <- ggplot(
    clogit_plot_df,
    aes(
      x = odds_ratio,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 1,
      linetype = "dashed",
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = odds_ratio_low,
        xmax = odds_ratio_high
      ),
      position = position_dodge(width = 0.72),
      height = 0.15,
      linewidth = 0.45,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.72),
      size = 2.4,
      stroke = 0.7,
      color = "black"
    ) +
    scale_x_log10(
      breaks = c(
        0.6,
        0.8,
        1.0,
        1.25,
        1.5,
        2.0
      ),
      labels = c(
        "0.6",
        "0.8",
        "1.0",
        "1.25",
        "1.5",
        "2.0"
      )
    ) +
    scale_shape_manual(
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotdash",
        "5政党" = "twodash"
      )
    ) +
    labs(
      x = "オッズ比",
      y = NULL,
      shape = "政党数選択肢",
      linetype = "政党数選択肢"
    ) +
    theme_bw(base_size = 12) +
    theme(
      legend.position = "bottom",
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      plot.title = element_text(face = "bold"),
      axis.text.y = element_text(size = 9)
    )

  print(p_clogit_or)

  save_plot(
    "clogit_oddsratio_nocov.png",
    p_clogit_or,
    width = 10.5,
    height = 8.5
  )


  relative_cue_map <- c(
    policy_position = "party",
    government_status = "party",
    seats = "party",
    gdp_growth = "economic",
    nikkei = "economic",
    cpi = "economic",
    unemployment = "economic"
  )

  mean_absolute_pairwise_difference <- function(x) {
    x <- x[is.finite(x)]

    if (length(x) < 2) {
      return(NA_real_)
    }

    pairwise_differences <- combn(
      x,
      2,
      FUN = function(z) abs(z[1] - z[2])
    )

    mean(pairwise_differences)
  }

  linear_slope <- function(y, x) {
    keep <- is.finite(y) & is.finite(x)
    y <- y[keep]
    x <- x[keep]

    if (length(y) < 2 || length(unique(x)) < 2) {
      return(NA_real_)
    }

    unname(coef(lm(y ~ x))[2])
  }

  bootstrap_two_sided_p <- function(x) {
    x <- x[is.finite(x)]
    B_valid <- length(x)

    if (B_valid == 0) {
      return(NA_real_)
    }

    p_lower <- (1 + sum(x <= 0)) / (B_valid + 1)
    p_upper <- (1 + sum(x >= 0)) / (B_valid + 1)

    min(1, 2 * min(p_lower, p_upper))
  }

  safe_quantile <- function(x, probability) {
    x <- x[is.finite(x)]

    if (length(x) == 0) {
      return(NA_real_)
    }

    unname(
      quantile(
        x,
        probs = probability,
        type = 6,
        na.rm = TRUE
      )
    )
  }

  prepare_relative_cue_analysis <- function(data, cue_map) {
    attributes <- names(cue_map)

    required_columns <- c(
      "ID",
      "party_n",
      "selected",
      attributes
    )

    missing_columns <- setdiff(
      required_columns,
      names(data)
    )

    if (length(missing_columns) > 0) {
      stop("Check relative weight")
    }

    if (!all(unname(cue_map) %in% c("party", "economic"))) {
      stop("Check relative weight")
    }

    analysis_data <- data %>%
      select(
        ID,
        party_n,
        selected,
        all_of(attributes)
      ) %>%
      mutate(
        ID = as.character(ID),
        party_n = as.integer(as.character(party_n)),
        selected = as.integer(selected),
        across(
          all_of(attributes),
          as.character
        )
      ) %>%
      filter(
        !is.na(ID),
        party_n %in% 2:5,
        selected %in% c(0L, 1L)
      )

    observed_conditions <- sort(
      unique(analysis_data$party_n)
    )

    if (!identical(observed_conditions, 2:5)) {
      stop("Check")
    }

    long_data <- analysis_data %>%
      pivot_longer(
        cols = all_of(attributes),
        names_to = "attribute",
        values_to = "level"
      ) %>%
      filter(
        !is.na(level),
        level != ""
      )

    expected_cells <- long_data %>%
      distinct(
        attribute,
        level
      ) %>%
      mutate(
        attribute_order = match(
          attribute,
          attributes
        )
      ) %>%
      arrange(
        attribute_order,
        attribute,
        level
      ) %>%
      select(-attribute_order) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    respondent_cell <- long_data %>%
      group_by(
        party_n,
        ID,
        attribute,
        level
      ) %>%
      summarise(
        y_sum = sum(selected),
        n_obs = n(),
        .groups = "drop"
      ) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    condition_objects <- lapply(
      2:5,
      function(n_value) {
        condition_data <- respondent_cell %>%
          filter(
            party_n == n_value
          )

        id_values <- sort(
          unique(condition_data$ID)
        )
        n_ids <- length(id_values)
        n_cells <- nrow(expected_cells)

        if (n_ids == 0) {
          stop("Check")
        }

        y_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        n_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        row_index <- match(
          condition_data$ID,
          id_values
        )
        column_index <- match(
          condition_data$cell_key,
          expected_cells$cell_key
        )

        y_matrix[cbind(row_index, column_index)] <-
          condition_data$y_sum
        n_matrix[cbind(row_index, column_index)] <-
          condition_data$n_obs

        if (any(colSums(n_matrix) == 0)) {
          missing_cells <- expected_cells$cell_key[
            colSums(n_matrix) == 0
          ]

          stop("Check attributes")
        }

        list(
          party_n = n_value,
          ids = id_values,
          cell_info = expected_cells,
          y_matrix = y_matrix,
          n_matrix = n_matrix
        )
      }
    )

    names(condition_objects) <- as.character(2:5)

    list(
      cue_map = cue_map,
      attributes = attributes,
      conditions = condition_objects
    )
  }

  estimate_relative_cue_indices <- function(
      prepared,
      cluster_weights = NULL
  ) {
    condition_results <- lapply(
      names(prepared$conditions),
      function(condition_name) {
        object <- prepared$conditions[[condition_name]]

        if (is.null(cluster_weights)) {
          weights <- rep(
            1,
            length(object$ids)
          )
        } else {
          weights <- cluster_weights[[condition_name]]
        }

        if (length(weights) != length(object$ids)) {
          stop("Check")
        }

        numerator <- as.numeric(
          crossprod(
            weights,
            object$y_matrix
          )
        )

        denominator <- as.numeric(
          crossprod(
            weights,
            object$n_matrix
          )
        )

        if (any(denominator <= 0)) {
          stop("Check attributes")
        }

        marginal_means <- numerator / denominator

        mm_table <- object$cell_info %>%
          transmute(
            party_n = object$party_n,
            attribute,
            level,
            marginal_mean = marginal_means
          )

        attribute_table <- mm_table %>%
          group_by(
            party_n,
            attribute
          ) %>%
          summarise(
            importance_pairwise =
              mean_absolute_pairwise_difference(
                marginal_mean
              ),
            n_levels = n(),
            .groups = "drop"
          ) %>%
          mutate(
            cue_family = unname(
              prepared$cue_map[attribute]
            ),
            baseline_selection_probability = 1 / party_n,
            importance_pairwise_adjusted =
              importance_pairwise /
                baseline_selection_probability
          )

        cue_table_long <- attribute_table %>%
          group_by(
            party_n,
            cue_family
          ) %>%
          summarise(
            importance_pairwise = mean(
              importance_pairwise,
              na.rm = TRUE
            ),
            importance_pairwise_adjusted = mean(
              importance_pairwise_adjusted,
              na.rm = TRUE
            ),
            .groups = "drop"
          )

        party_table <- cue_table_long %>%
          filter(
            cue_family == "party"
          ) %>%
          transmute(
            party_n,
            party_importance_pairwise =
              importance_pairwise,
            party_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        economic_table <- cue_table_long %>%
          filter(
            cue_family == "economic"
          ) %>%
          transmute(
            party_n,
            economic_importance_pairwise =
              importance_pairwise,
            economic_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        cue_table <- full_join(
          party_table,
          economic_table,
          by = "party_n"
        ) %>%
          mutate(
            baseline_selection_probability = 1 / party_n,

            total_importance_pairwise =
              party_importance_pairwise +
              economic_importance_pairwise,

            total_importance_pairwise_adjusted =
              party_importance_pairwise_adjusted +
              economic_importance_pairwise_adjusted,

            relative_party_weight_pairwise = if_else(
              total_importance_pairwise > 0,
              party_importance_pairwise /
                total_importance_pairwise,
              NA_real_
            ),

            relative_economic_weight_pairwise =
              1 - relative_party_weight_pairwise,

            relative_party_weight_pairwise_adjusted = if_else(
              total_importance_pairwise_adjusted > 0,
              party_importance_pairwise_adjusted /
                total_importance_pairwise_adjusted,
              NA_real_
            ),

            relative_economic_weight_pairwise_adjusted =
              1 - relative_party_weight_pairwise_adjusted,

            adjustment_identity_difference =
              relative_party_weight_pairwise_adjusted -
                relative_party_weight_pairwise
          )

        if (
          any(
            abs(cue_table$adjustment_identity_difference) > 1e-10,
            na.rm = TRUE
          )
        ) {
          stop("Check relative weight")
        }

        list(
          marginal_means = mm_table,
          attribute_importance = attribute_table,
          cue_importance = cue_table
        )
      }
    )

    list(
      marginal_means = bind_rows(
        lapply(
          condition_results,
          function(x) x$marginal_means
        )
      ),
      attribute_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$attribute_importance
        )
      ),
      cue_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$cue_importance
        )
      ) %>%
        arrange(party_n)
    )
  }

  estimate_relative_cue_slopes <- function(cue_importance) {
    cue_importance <- cue_importance %>%
      arrange(party_n)

    if (!identical(cue_importance$party_n, 2:5)) {
      stop("Check relative weight")
    }

    x <- cue_importance$party_n

    c(
      relative_party_weight_pairwise =
        linear_slope(
          cue_importance$relative_party_weight_pairwise,
          x
        ),

      party_importance_pairwise =
        linear_slope(
          cue_importance$party_importance_pairwise,
          x
        ),

      economic_importance_pairwise =
        linear_slope(
          cue_importance$economic_importance_pairwise,
          x
        ),

      party_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$party_importance_pairwise_adjusted,
          x
        ),

      economic_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$economic_importance_pairwise_adjusted,
          x
        )
    )
  }

  run_relative_cue_bootstrap <- function(
      prepared,
      B,
      seed,
      progress_every = 100
  ) {
    set.seed(seed)

    condition_results <- vector(
      "list",
      B
    )

    slope_names <- c(
      "relative_party_weight_pairwise",
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted"
    )

    slope_matrix <- matrix(
      NA_real_,
      nrow = B,
      ncol = length(slope_names),
      dimnames = list(
        NULL,
        slope_names
      )
    )

    for (b in seq_len(B)) {
      cluster_weights <- lapply(
        prepared$conditions,
        function(object) {
          n_ids <- length(object$ids)

          sampled_positions <- sample.int(
            n = n_ids,
            size = n_ids,
            replace = TRUE
          )

          tabulate(
            sampled_positions,
            nbins = n_ids
          )
        }
      )

      bootstrap_estimates <- estimate_relative_cue_indices(
        prepared = prepared,
        cluster_weights = cluster_weights
      )

      condition_results[[b]] <-
        bootstrap_estimates$cue_importance %>%
        select(
          party_n,
          party_importance_pairwise,
          economic_importance_pairwise,
          party_importance_pairwise_adjusted,
          economic_importance_pairwise_adjusted,
          relative_party_weight_pairwise
        ) %>%
        mutate(
          bootstrap_replication = b,
          .before = 1
        )

      slope_matrix[b, ] <- estimate_relative_cue_slopes(
        bootstrap_estimates$cue_importance
      )

      if (
        progress_every > 0 &&
        (b %% progress_every == 0 || b == B)
      ) {
        message("Bootstrap: ", b, "/", B)
      }
    }

    list(
      condition_estimates = bind_rows(
        condition_results
      ),
      slopes = as_tibble(
        slope_matrix
      ) %>%
        mutate(
          bootstrap_replication = row_number(),
          .before = 1
        )
    )
  }

  summarise_condition_intervals <- function(
      observed_cue_importance,
      bootstrap_condition_results
  ) {
    statistics <- c(
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted",
      "relative_party_weight_pairwise"
    )

    observed_long <- observed_cue_importance %>%
      select(
        party_n,
        all_of(statistics)
      ) %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "estimate"
      )

    bootstrap_long <- bootstrap_condition_results %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "value"
      ) %>%
      group_by(
        party_n,
        statistic
      ) %>%
      summarise(
        conf_low = safe_quantile(
          value,
          0.025
        ),
        conf_high = safe_quantile(
          value,
          0.975
        ),
        .groups = "drop"
      )

    observed_long %>%
      left_join(
        bootstrap_long,
        by = c(
          "party_n",
          "statistic"
        )
      )
  }

  summarise_slope_inference <- function(
      observed_slopes,
      bootstrap_slopes
  ) {
    statistic_names <- names(observed_slopes)

    map_dfr(
      statistic_names,
      function(statistic_name) {
        bootstrap_values <- bootstrap_slopes[[statistic_name]]
        bootstrap_values <- bootstrap_values[
          is.finite(bootstrap_values)
        ]

        expected_direction <- case_when(
          statistic_name ==
            "economic_importance_pairwise" ~ "negative",
          statistic_name %in% c(
            "party_importance_pairwise",
            "relative_party_weight_pairwise",
            "party_importance_pairwise_adjusted"
          ) ~ "positive",
          TRUE ~ "none"
        )

        analysis_role <- case_when(
          statistic_name %in% c(
            "party_importance_pairwise_adjusted",
            "economic_importance_pairwise_adjusted"
          ) ~ "exploratory_choice_set_adjusted",
          statistic_name == "relative_party_weight_pairwise" ~
            "derived_relative_share",
          TRUE ~ "manuscript_primary_unadjusted"
        )

        estimate <- unname(
          observed_slopes[[statistic_name]]
        )

        tibble(
          study = "Study 1",
          statistic = statistic_name,
          estimate = estimate,
          conf_low = safe_quantile(
            bootstrap_values,
            0.025
          ),
          conf_high = safe_quantile(
            bootstrap_values,
            0.975
          ),
          p_value_two_sided =
            bootstrap_two_sided_p(
              bootstrap_values
            ),
          expected_direction = expected_direction,
          analysis_role = analysis_role,
          estimate_in_expected_direction = case_when(
            expected_direction == "positive" ~ estimate > 0,
            expected_direction == "negative" ~ estimate < 0,
            TRUE ~ NA
          )
        )
      }
    )
  }

  relative_cue_prepared <- prepare_relative_cue_analysis(
    data = conjoint_all_m,
    cue_map = relative_cue_map
  )

  relative_cue_observed <- estimate_relative_cue_indices(
    prepared = relative_cue_prepared
  )

  relative_cue_observed_slopes <- estimate_relative_cue_slopes(
    relative_cue_observed$cue_importance
  )

  write_csv_safely(
    relative_cue_observed$marginal_means,
    "study1_relative_cue_marginal_means.csv"
  )

  write_csv_safely(
    relative_cue_observed$attribute_importance,
    "study1_relative_cue_attribute_importance.csv"
  )

  write_csv_safely(
    relative_cue_observed$cue_importance,
    "study1_relative_cue_importance_and_weight.csv"
  )

  relative_condition_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study1_relative_cue_condition_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  relative_slope_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study1_relative_cue_slope_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  use_saved_relative_bootstrap <-
    !rerun_relative_cue_bootstrap &&
    file.exists(relative_condition_bootstrap_file) &&
    file.exists(relative_slope_bootstrap_file)

  if (use_saved_relative_bootstrap) {
    message("Bootstrap cache")

    relative_cue_condition_bootstrap <- readr::read_csv(
      relative_condition_bootstrap_file,
      show_col_types = FALSE
    )

    relative_cue_slope_bootstrap <- readr::read_csv(
      relative_slope_bootstrap_file,
      show_col_types = FALSE
    )

    saved_B_condition <- n_distinct(
      relative_cue_condition_bootstrap$bootstrap_replication
    )
    saved_B_slope <- n_distinct(
      relative_cue_slope_bootstrap$bootstrap_replication
    )

    if (
      saved_B_condition != relative_cue_bootstrap_B ||
      saved_B_slope != relative_cue_bootstrap_B
    ) {
      message("Bootstrap cache")
      use_saved_relative_bootstrap <- FALSE
    }
  }

  if (!use_saved_relative_bootstrap) {
    relative_cue_bootstrap <- run_relative_cue_bootstrap(
      prepared = relative_cue_prepared,
      B = relative_cue_bootstrap_B,
      seed = relative_cue_bootstrap_seed,
      progress_every = relative_cue_bootstrap_progress_every
    )

    relative_cue_condition_bootstrap <-
      relative_cue_bootstrap$condition_estimates

    relative_cue_slope_bootstrap <-
      relative_cue_bootstrap$slopes

    readr::write_csv(
      relative_cue_condition_bootstrap,
      relative_condition_bootstrap_file
    )

    readr::write_csv(
      relative_cue_slope_bootstrap,
      relative_slope_bootstrap_file
    )
  }

  relative_cue_condition_intervals <- summarise_condition_intervals(
    observed_cue_importance =
      relative_cue_observed$cue_importance,
    bootstrap_condition_results =
      relative_cue_condition_bootstrap
  )

  relative_cue_slope_inference <- summarise_slope_inference(
    observed_slopes =
      relative_cue_observed_slopes,
    bootstrap_slopes =
      relative_cue_slope_bootstrap
  )

  write_csv_safely(
    relative_cue_condition_intervals,
    "study1_relative_cue_condition_intervals.csv"
  )

  write_csv_safely(
    relative_cue_slope_inference,
    "study1_relative_cue_slope_inference.csv"
  )

  relative_cue_primary_result <- relative_cue_slope_inference %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    )

  cat("\nStudy 1:相対比重の線形傾向\n")
  print(relative_cue_primary_result)


  relative_x_offset <- 0.075

  relative_panel_a_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise",
        "economic_importance_pairwise"
      )
    ) %>%
    mutate(
      cue_family = recode(
        statistic,
        party_importance_pairwise = "政党手がかり",
        economic_importance_pairwise = "経済手がかり"
      ),
      cue_family = factor(
        cue_family,
        levels = c(
          "政党手がかり",
          "経済手がかり"
        )
      ),
      x_plot = case_when(
        cue_family == "政党手がかり" ~
          party_n + relative_x_offset,
        cue_family == "経済手がかり" ~
          party_n - relative_x_offset,
        TRUE ~ as.numeric(party_n)
      ),
      value_label = sprintf(
        "%.3f",
        estimate
      )
    )

  relative_panel_b_data <- relative_cue_condition_intervals %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    ) %>%
    mutate(
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_adjusted_label_map <- relative_panel_a_data %>%
    distinct(
      statistic,
      cue_family
    ) %>%
    mutate(
      statistic = paste0(
        statistic,
        "_adjusted"
      ),
      cue_family = as.character(
        cue_family
      )
    )

  relative_panel_adjusted_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise_adjusted",
        "economic_importance_pairwise_adjusted"
      )
    ) %>%
    left_join(
      relative_adjusted_label_map,
      by = "statistic"
    ) %>%
    mutate(
      cue_family = factor(
        cue_family,
        levels = levels(
          relative_panel_a_data$cue_family
        )
      ),
      x_plot = if_else(
        as.integer(cue_family) == 1L,
        party_n + relative_x_offset,
        party_n - relative_x_offset
      ),
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_condition_suffix <- if (
    "政党名手がかり" %in%
      levels(relative_panel_a_data$cue_family)
  ) {
    "選択肢"
  } else {
    "政党"
  }

  relative_condition_axis_title <- if (
    relative_condition_suffix == "選択肢"
  ) {
    "政治経済状況の選択肢数"
  } else {
    "政党選択肢数"
  }

  relative_figure_font_family <- if (
    .Platform$OS.type == "windows"
  ) {
    "Yu Gothic"
  } else {
    "sans"
  }

  relative_theme_japanese_bw <- theme_bw(
    base_size = 12,
    base_family = relative_figure_font_family
  ) +
    theme(
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(
        linewidth = 0.30,
        color = "grey88"
      ),
      panel.border = element_rect(
        linewidth = 0.65,
        color = "black"
      ),
      axis.text = element_text(
        color = "black"
      ),
      axis.title = element_text(
        color = "black"
      ),
      plot.title = element_text(
        size = 12.5,
        face = "bold",
        hjust = 0
      ),
      plot.subtitle = element_text(
        size = 9.5,
        hjust = 0,
        margin = margin(
          b = 8
        )
      ),
      legend.position = "top",
      legend.justification = "center",
      legend.key.width = grid::unit(
        1.25,
        "cm"
      ),
      plot.margin = margin(
        8,
        10,
        8,
        8
      )
    )

  relative_panel_a <- ggplot(
    relative_panel_a_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = c(
        "政党手がかり" = "solid",
        "経済手がかり" = "dashed"
      )
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "政党"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_number(
        accuracy = 0.005
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:両手がかりの絶対的重要度",
      subtitle = "",
      x = "政党選択肢数",
      y = "手がかり重要度",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_adjusted_linetypes <- setNames(
    c(
      "solid",
      "dashed"
    ),
    levels(
      relative_panel_adjusted_data$cue_family
    )
  )

  relative_panel_adjusted <- ggplot(
    relative_panel_adjusted_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = relative_adjusted_linetypes
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        relative_condition_suffix
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:選択肢数調整済み重要度",
      subtitle =
        "未調整重要度 ÷ 平均選択確率(1/選択肢数)",
      x = relative_condition_axis_title,
      y = "平均選択確率に対する水準間差",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_b_range <- range(
    c(
      relative_panel_b_data$conf_low,
      relative_panel_b_data$conf_high,
      0.5
    ),
    na.rm = TRUE
  )

  relative_b_padding <- max(
    0.025,
    0.10 * diff(relative_b_range)
  )

  relative_b_lower <- max(
    0,
    floor(
      20 *
        (relative_b_range[1] - relative_b_padding)
    ) / 20
  )

  relative_b_upper <- min(
    1,
    ceiling(
      20 *
        (relative_b_range[2] + relative_b_padding)
    ) / 20
  )

  if (relative_b_lower >= relative_b_upper) {
    relative_b_lower <- max(
      0,
      relative_b_lower - 0.05
    )
    relative_b_upper <- min(
      1,
      relative_b_upper + 0.05
    )
  }

  relative_panel_b <- ggplot(
    relative_panel_b_data,
    aes(
      x = party_n,
      y = estimate
    )
  ) +
    geom_hline(
      yintercept = 0.5,
      linetype = "dashed",
      linewidth = 0.55,
      color = "black"
    ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "政党"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      breaks = seq(
        relative_b_lower,
        relative_b_upper,
        by = 0.05
      ),
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.05,
          0.08
        )
      )
    ) +
    coord_cartesian(
      ylim = c(
        relative_b_lower,
        relative_b_upper
      )
    ) +
    labs(
      title = "B:相対的な政党手がかりの比重",
      subtitle =
        "政党手がかり重要度 ÷(政党手がかり重要度+経済手がかり重要度)",
      x = "政党選択肢数",
      y = "相対的な政党手がかり比重"
    ) +
    relative_theme_japanese_bw +
    theme(
      legend.position = "none"
    )

  relative_panel_c <- relative_panel_b +
    labs(
      title = paste0(
        "B:相対的な",
        levels(relative_panel_a_data$cue_family)[1],
        "の比重"
      )
    )

  figure_relative_weight_jp <- (
    relative_panel_a |
      relative_panel_b
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_jp
  )

  save_plot(
    "fig_study1_relative_cue_weight_jp_bw.png",
    figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      "fig_study1_relative_cue_weight_jp_bw.pdf"
    ),
    plot = figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  figure_relative_weight_adjusted_jp <- (
    relative_panel_adjusted |
      relative_panel_c
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_adjusted_jp
  )

  relative_adjusted_figure_stub <- paste0(
    "fig_study",
    stringr::str_extract(
      study_label,
      "[123]"
    ),
    "_relative_cue_weight_choice_set_adjusted_jp_bw"
  )

  save_plot(
    paste0(
      relative_adjusted_figure_stub,
      ".png"
    ),
    figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      paste0(
        relative_adjusted_figure_stub,
        ".pdf"
      )
    ),
    plot = figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  relative_cue_results <- list(
    prepared = relative_cue_prepared,
    marginal_means =
      relative_cue_observed$marginal_means,
    attribute_importance =
      relative_cue_observed$attribute_importance,
    cue_importance =
      relative_cue_observed$cue_importance,
    observed_slopes =
      relative_cue_observed_slopes,
    condition_bootstrap =
      relative_cue_condition_bootstrap,
    slope_bootstrap =
      relative_cue_slope_bootstrap,
    condition_intervals =
      relative_cue_condition_intervals,
    slope_inference =
      relative_cue_slope_inference,
    primary_result =
      relative_cue_primary_result,
    plots = list(
      absolute_importance = relative_panel_a,
      choice_set_adjusted_importance =
        relative_panel_adjusted,
      relative_party_weight = relative_panel_b,
      relative_party_weight_panel_c =
        relative_panel_c,
      combined = figure_relative_weight_jp,
      combined_with_choice_set_adjustment =
        figure_relative_weight_adjusted_jp
    )
  )

  saveRDS(
    relative_cue_results,
    file = file.path(
      output_dir,
      "study1_relative_cue_results.rds"
    )
  )


  saveRDS(
    list(
      settings = list(
        require_initial_consent = require_initial_consent,
        require_final_consent = require_final_consent,
        require_attention_check = require_attention_check,
        require_manipulation_check = require_manipulation_check
      ),
      sample_flow = sample_flow,
      n_by_party = n_by_party,
      valid_ids = valid_ids,
      conjoint_all = conjoint_all,
      conjoint_all_m = conjoint_all_m,
      covar_id = covar_id,
      models_by_party_n_nocov = models_by_party_n_nocov,
      models_by_party_n_cov = models_by_party_n_cov,
      m_interaction = m_interaction,
      models_clogit_nocov = models_clogit_nocov,
      relative_cue = relative_cue_results,
      plots = list(
        amce_cov = p_amce_cov_main,
        amce_nocov = p_amce_nocov_appendix,
        interaction = p_interaction,
        heatmap = p_heat_amce,
        heatmap_rank = p_heat_amce_rank,
        clogit_odds_ratio = p_clogit_or,
        relative_cue_weight = figure_relative_weight_jp,
        relative_cue_weight_choice_set_adjusted =
          figure_relative_weight_adjusted_jp
      )
    ),
    file = file.path(output_dir, "study1_analysis_objects.rds")
  )

  capture.output(
    sessionInfo(),
    file = file.path(output_dir, "sessionInfo.txt")
  )

  cat("
Done: ", normalizePath(output_dir), "
", sep = "")

  environment()
})

A.3 実験2:本文の図6

# 本文コード
study2_env <- local({
required_packages <- c(
    "dplyr",
    "tidyr",
    "stringr",
    "purrr",
    "readr",
    "fixest",
    "tibble",
    "forcats",
    "ggplot2",
    "scales",
    "survival",
    "ggtext",
    "patchwork"
  )

  missing_packages <- required_packages[
    !vapply(required_packages, requireNamespace, logical(1), quietly = TRUE)
  ]

  if (length(missing_packages) > 0) {
    stop("No packages")
  }

  library(dplyr)
  library(tidyr)
  library(stringr)
  library(purrr)
  library(readr)
  library(fixest)
  library(tibble)
  library(forcats)
  library(ggplot2)
  library(scales)
  library(survival)
  library(patchwork)

  data_file <- unified_config$study2$data_file
  output_dir <- unified_config$study2$output_dir

  dir.create(output_dir, showWarnings = FALSE, recursive = TRUE)

  require_initial_consent <- TRUE
  require_final_consent <- TRUE
  final_consent_var <- "Q8.1"

  require_attention_check <- TRUE
  require_manipulation_check <- TRUE

  attention_check_var <- "Q25.1_11"
  attention_check_correct <- "3"

  relative_cue_bootstrap_B <- unified_config$relative_cue_bootstrap_B
  relative_cue_bootstrap_seed <- unified_config$relative_cue_bootstrap_seed + 2L
  relative_cue_bootstrap_progress_every <- unified_config$relative_cue_bootstrap_progress_every

  rerun_relative_cue_bootstrap <- unified_config$rerun_relative_cue_bootstrap


  norm_text <- function(x) {
    x %>%
      as.character() %>%
      str_squish() %>%
      str_replace_all("~", "~") %>%
      str_replace_all("〜", "~")
  }

  as_num <- function(x) {
    suppressWarnings(readr::parse_number(norm_text(x)))
  }

  is_response_code <- function(x, code) {
    x_norm <- norm_text(x)
    code_chr <- as.character(code)

    x_norm == code_chr |
      stringr::str_detect(x_norm, paste0("\\(", code_chr, "\\)$"))
  }

  first_existing <- function(dat, candidates) {
    out <- candidates[candidates %in% names(dat)]
    if (length(out) == 0) NA_character_ else out[1]
  }

  get_var <- function(dat, candidates) {
    v <- first_existing(dat, candidates)
    if (is.na(v)) {
      rep(NA_character_, nrow(dat))
    } else {
      dat[[v]]
    }
  }

  relevel_if_present <- function(x, ref) {
    x <- factor(x)
    if (ref %in% levels(x)) {
      relevel(x, ref = ref)
    } else {
      x
    }
  }

  factor_miss <- function(x, miss = "欠損・無回答") {
    x <- norm_text(x)
    x[is.na(x) | x == "" | x == "NA"] <- miss
    factor(x)
  }

  mean_impute <- function(x) {
    x <- as.numeric(x)
    miss <- as.integer(is.na(x))

    if (all(is.na(x))) {
      value <- x
    } else {
      value <- ifelse(is.na(x), mean(x, na.rm = TRUE), x)
    }

    list(value = value, miss = miss)
  }

  write_csv_safely <- function(x, filename) {
    readr::write_csv(x, file.path(output_dir, filename), na = "")
  }

  save_plot <- function(filename, plot, width, height, dpi = 300) {
    ggplot2::ggsave(
      filename = file.path(output_dir, filename),
      plot = plot,
      width = width,
      height = height,
      dpi = dpi
    )
  }


  if (!file.exists(data_file)) {
    stop("Check data")
  }

  raw <- readr::read_csv(
    data_file,
    col_types = cols(.default = col_character()),
    show_col_types = FALSE,
    name_repair = "minimal"
  )


  if (require_final_consent) {
    final_consent_var <- detect_final_consent_column(
      raw = raw,
      preferred_candidates = c("Q8.1", "Q9.1", "Q10.1"),
      study_label = "Study 2"
    )
  }

  if (require_attention_check) {
    attention_check_var <- detect_attention_check_column(
      raw = raw,
      preferred_candidates = c("Q25.1_11", "Q25.1_10"),
      study_label = "Study 2"
    )
  }

  df_header_removed <- raw %>%
    filter(
      !is.na(ResponseId),
      ResponseId != "",
      !str_detect(
        norm_text(ResponseId),
        "^(Response ID|回答ID)$|ImportId"
      )
    ) %>%
    mutate(ID = as.character(ResponseId))

  duplicate_ids <- df_header_removed %>%
    count(ID) %>%
    filter(n > 1)

  if (nrow(duplicate_ids) > 0) {
    print(duplicate_ids)
    stop("Check")
  }

  sample_flow <- tibble(
    stage = "Qualtrics質問文行を除外後",
    n = nrow(df_header_removed)
  )

  df <- df_header_removed

  if (require_initial_consent) {
    if (!"Q1.1" %in% names(df)) {
      stop("Check initial consent")
    }

    df <- df %>%
      filter(
        is_response_code(Q1.1, 1) |
          str_detect(norm_text(Q1.1), "趣旨に同意して.*協力する")
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(stage = "初回同意 Q1.1 = 1", n = nrow(df))
    )
  }

  if (require_final_consent) {
    if (is.na(final_consent_var) || !final_consent_var %in% names(df)) {
      stop("Check final consent")
    }

    df <- df %>%
      filter(
        is_response_code(.data[[final_consent_var]], 1) |
          str_detect(
            norm_text(.data[[final_consent_var]]),
            "同意し.*回答結果を送信する"
          )
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(
        stage = paste0("最終同意 ", final_consent_var, " = 1"),
        n = nrow(df)
      )
    )
  }

  if (require_attention_check) {
    if (!attention_check_var %in% names(df)) {
      stop("Check attention item")
    }

    attention_check_correct <- detect_attention_correct_code(
      df[[attention_check_var]],
      displayed_answer = 3L,
      recoded_answer = 6L,
      study_label = "Study 2"
    )

    df <- df %>%
      filter(
        is_response_code(
          .data[[attention_check_var]],
          attention_check_correct
        )
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(
        stage = paste0(
          "指示項目正答(",
          attention_check_var,
          "、保存コード=",
          attention_check_correct,
          ")"
        ),
        n = nrow(df)
      )
    )
  }

  print(sample_flow)
  write_csv_safely(sample_flow, "sample_flow_before_conjoint.csv")


  choice_map <- detect_conjoint_choice_map(
    raw = raw,
    party_numbers = 2:5,
    study_label = "Study 2"
  )

  manipulation_map <- detect_manipulation_map(
    raw = raw,
    choice_map = choice_map,
    study_label = "Study 2"
  )

  write_csv_safely(choice_map, "detected_choice_question_map.csv")
  write_csv_safely(manipulation_map, "detected_manipulation_question_map.csv")


  level_to_attr_var <- function(x) {
    x <- norm_text(x)

    case_when(
      x %in% c("右派・保守的", "中道", "左派・革新的") ~
        "policy_position",

      x %in% c("与党", "野党") ~
        "government_status",

      str_detect(x, "GDP成長率") ~
        "gdp_growth",

      str_detect(x, "日経平均") ~
        "nikkei",

      x %in% c("10以下", "10~49", "50~99", "100~199", "200以上") ~
        "seats",

      str_detect(x, "CPI|物価") ~
        "cpi",

      str_detect(x, "失業率|雇用") ~
        "unemployment",

      TRUE ~ NA_character_
    )
  }

  required_attr_vars <- c(
    "policy_position",
    "government_status",
    "gdp_growth",
    "nikkei",
    "seats",
    "cpi",
    "unemployment"
  )

  allowed_levels <- list(
    policy_position = c("右派・保守的", "中道", "左派・革新的"),
    government_status = c("与党", "野党"),
    gdp_growth = c(
      "GDP成長率±0%",
      "GDP成長率プラス1%",
      "GDP成長率マイナス1%"
    ),
    nikkei = c(
      "日経平均前月同期比プラス1000円",
      "日経平均前月同期比マイナス1000円",
      "日経平均前月同期比変わらず"
    ),
    seats = c("10以下", "10~49", "50~99", "100~199", "200以上"),
    cpi = c(
      "CPI前期比±0ポイント",
      "CPI前期比プラス1ポイント",
      "CPI前期比マイナス1ポイント"
    ),
    unemployment = c(
      "失業率前期比±0%",
      "失業率前期比プラス1%",
      "失業率前期比マイナス1%"
    )
  )


  make_profile_long <- function(dat, n_party) {

    map_n <- choice_map %>%
      filter(party_n == n_party)

    qvars <- map_n$choice_var

    missing_q <- setdiff(qvars, names(dat))
    if (length(missing_q) > 0) {
      stop("Check choice columns")
    }

    dat_n <- dat %>%
      filter(if_any(all_of(qvars), ~ !is.na(.x) & norm_text(.x) != ""))

    if (require_manipulation_check) {
      manipulation_row <- manipulation_map %>%
        filter(party_n == n_party)

      manipulation_var <- manipulation_row$manipulation_var
      correct_answer <- manipulation_row$correct_answer

      if (!manipulation_var %in% names(dat_n)) {
        stop("Check manipulation item")
      }

      dat_n <- dat_n %>%
        filter(
          is_response_code(
            .data[[manipulation_var]],
            correct_answer
          )
        )
    }

    choice_long <- dat_n %>%
      select(ID, all_of(qvars)) %>%
      pivot_longer(
        cols = all_of(qvars),
        names_to = "choice_var",
        values_to = "choice_raw"
      ) %>%
      left_join(map_n, by = "choice_var") %>%
      mutate(choice = parse_choice_position(choice_raw)) %>%
      filter(!is.na(choice)) %>%
      select(ID, party_n, task, choice)

    invalid_choice <- choice_long %>%
      filter(choice < 1 | choice > n_party)

    if (nrow(invalid_choice) > 0) {
      print(invalid_choice)
      stop("Check choice values")
    }

    duplicate_choice <- choice_long %>%
      count(ID, task) %>%
      filter(n != 1)

    if (nrow(duplicate_choice) > 0) {
      print(duplicate_choice)
      stop("Check duplicate choices")
    }

    level_regex <- paste0(
      "^S2_P", n_party,
      "_F_([1-5])_([1-", n_party, "])_([1-7])$"
    )

    level_cols <- names(dat_n)[str_detect(names(dat_n), level_regex)]

    expected_level_cols <- 5 * n_party * 7
    if (length(level_cols) != expected_level_cols) {
      stop("Check attributes")
    }

    level_long <- dat_n %>%
      select(ID, all_of(level_cols)) %>%
      pivot_longer(
        cols = all_of(level_cols),
        names_to = "fvar",
        values_to = "level"
      ) %>%
      extract(
        fvar,
        into = c("task", "profile", "attr_order"),
        regex = level_regex,
        convert = TRUE
      ) %>%
      mutate(level = norm_text(level)) %>%
      filter(
        task %in% 1:5,
        profile %in% 1:n_party,
        attr_order %in% 1:7,
        !is.na(level),
        level != ""
      ) %>%
      mutate(attr_var = level_to_attr_var(level))

    unknown_levels <- level_long %>%
      filter(is.na(attr_var)) %>%
      distinct(level)

    if (nrow(unknown_levels) > 0) {
      print(unknown_levels)
      stop("Check attributes")
    }

    profile_attribute_count <- level_long %>%
      count(ID, task, profile, name = "n_attribute_rows") %>%
      filter(n_attribute_rows != 7)

    if (nrow(profile_attribute_count) > 0) {
      print(head(profile_attribute_count, 50))
      stop("Check attributes")
    }

    duplicate_attribute <- level_long %>%
      count(ID, task, profile, attr_var) %>%
      filter(n != 1)

    if (nrow(duplicate_attribute) > 0) {
      print(head(duplicate_attribute, 50))
      stop("Check attributes")
    }

    profile_wide <- level_long %>%
      inner_join(choice_long, by = c("ID", "task")) %>%
      mutate(
        party_n = n_party,
        selected = as.integer(profile == choice),
        task_id = paste(ID, party_n, task, sep = "_"),
        profile_id = paste(ID, party_n, task, profile, sep = "_")
      ) %>%
      select(
        ID, party_n, task, profile, choice, selected,
        task_id, profile_id, attr_var, level
      ) %>%
      pivot_wider(
        names_from = attr_var,
        values_from = level,
        values_fn = list(level = ~ first(.x))
      )

    missing_attr <- setdiff(required_attr_vars, names(profile_wide))

    if (length(missing_attr) > 0) {
      stop("Check attributes")
    }

    profile_wide <- profile_wide %>%
      select(
        ID, party_n, task, profile, choice, selected,
        task_id, profile_id,
        all_of(required_attr_vars)
      ) %>%
      arrange(ID, task, profile)

    return(profile_wide)
  }


  conjoint_2 <- make_profile_long(df, 2)
  conjoint_3 <- make_profile_long(df, 3)
  conjoint_4 <- make_profile_long(df, 4)
  conjoint_5 <- make_profile_long(df, 5)

  conjoint_all_unfiltered <- bind_rows(
    conjoint_2,
    conjoint_3,
    conjoint_4,
    conjoint_5
  )


  id_task_check <- conjoint_all_unfiltered %>%
    group_by(ID, party_n, task) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    group_by(ID, party_n) %>%
    summarise(
      n_tasks = n_distinct(task),
      all_tasks_ok = all(n_profiles == party_n & selected_sum == 1),
      .groups = "drop"
    )

  valid_ids <- id_task_check %>%
    filter(n_tasks == 5, all_tasks_ok)

  conjoint_all <- conjoint_all_unfiltered %>%
    semi_join(valid_ids, by = c("ID", "party_n"))

  n_by_party <- valid_ids %>%
    count(party_n, name = "n") %>%
    complete(party_n = 2:5, fill = list(n = 0)) %>%
    arrange(party_n)

  n_total <- valid_ids %>%
    summarise(n = n_distinct(ID)) %>%
    pull(n)

  figure_n_labels <- bind_rows(
    tibble(
      position = "全サンプル",
      label = paste0("全サンプル, n=", scales::comma(n_total))
    ),
    n_by_party %>%
      mutate(
        position = paste0(party_n, "政党選択"),
        label = paste0("n=", scales::comma(n))
      ) %>%
      select(position, label)
  )

  cat("\n分析対象者数\n")
  print(n_by_party)
  cat("全サンプル n=", n_total, "\n", sep = "")

  write_csv_safely(id_task_check, "id_task_check.csv")
  write_csv_safely(valid_ids, "valid_ids.csv")
  write_csv_safely(n_by_party, "n_by_party.csv")
  write_csv_safely(figure_n_labels, "figure_n_labels.csv")


  check_profile <- conjoint_all %>%
    group_by(party_n, ID, task, task_id) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    count(party_n, n_profiles, selected_sum)

  print(check_profile)

  stopifnot(all(check_profile$n_profiles == check_profile$party_n))
  stopifnot(all(check_profile$selected_sum == 1))

  allowed_df <- enframe(allowed_levels, name = "name", value = "value") %>%
    unnest(value)

  unexpected_values <- conjoint_all %>%
    select(all_of(required_attr_vars)) %>%
    pivot_longer(
      cols = everything(),
      names_to = "name",
      values_to = "value"
    ) %>%
    filter(!is.na(value), value != "") %>%
    distinct(name, value) %>%
    anti_join(allowed_df, by = c("name", "value"))

  print(unexpected_values)
  stopifnot(nrow(unexpected_values) == 0)

  observed_levels <- conjoint_all %>%
    select(all_of(required_attr_vars)) %>%
    pivot_longer(
      cols = everything(),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    distinct(attribute, level) %>%
    arrange(attribute, level)

  write_csv_safely(check_profile, "profile_expansion_check.csv")
  write_csv_safely(observed_levels, "observed_attribute_levels.csv")
  write_csv_safely(conjoint_all, "study2_profile_level_data.csv")


  analysis_ids <- valid_ids %>%
    select(ID, party_n)

  attention_summary <- df %>%
    semi_join(analysis_ids, by = "ID") %>%
    transmute(
      ID,
      attention_response = norm_text(.data[[attention_check_var]]),
      attention_pass = is_response_code(
        .data[[attention_check_var]],
        attention_check_correct
      )
    ) %>%
    count(attention_response, attention_pass, name = "n") %>%
    arrange(desc(attention_pass), attention_response)

  manipulation_summary <- map_dfr(2:5, function(n_party) {
    manipulation_row <- manipulation_map %>%
      filter(party_n == n_party)

    v <- manipulation_row$manipulation_var
    correct <- manipulation_row$correct_answer

    df %>%
      semi_join(
        analysis_ids %>% filter(party_n == n_party),
        by = "ID"
      ) %>%
      transmute(
        party_n = n_party,
        response = norm_text(.data[[v]]),
        correct = is_response_code(.data[[v]], correct)
      ) %>%
      count(party_n, response, correct, name = "n")
  })

  write_csv_safely(attention_summary, "attention_check_summary.csv")
  write_csv_safely(manipulation_summary, "party_number_check_summary.csv")


  conjoint_all_m <- conjoint_all %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),

      policy_position = factor(
        policy_position,
        levels = c("中道", "右派・保守的", "左派・革新的")
      ),

      government_status = factor(
        government_status,
        levels = c("野党", "与党")
      ),

      gdp_growth = factor(
        gdp_growth,
        levels = c(
          "GDP成長率±0%",
          "GDP成長率プラス1%",
          "GDP成長率マイナス1%"
        )
      ),

      nikkei = factor(
        nikkei,
        levels = c(
          "日経平均前月同期比変わらず",
          "日経平均前月同期比プラス1000円",
          "日経平均前月同期比マイナス1000円"
        )
      ),

      seats = factor(
        seats,
        levels = c("10以下", "10~49", "50~99", "100~199", "200以上")
      ),

      cpi = factor(
        cpi,
        levels = c(
          "CPI前期比±0ポイント",
          "CPI前期比プラス1ポイント",
          "CPI前期比マイナス1ポイント"
        )
      ),

      unemployment = factor(
        unemployment,
        levels = c(
          "失業率前期比±0%",
          "失業率前期比プラス1%",
          "失業率前期比マイナス1%"
        )
      ),

      party_n_f = factor(
        as.character(party_n),
        levels = c("2", "3", "4", "5")
      )
    )

  attr_terms <- c(
    "policy_position",
    "government_status",
    "gdp_growth",
    "nikkei",
    "seats",
    "cpi",
    "unemployment"
  )


  formula_nocov <- as.formula(
    paste("selected ~", paste(attr_terms, collapse = " + "))
  )

  run_amce_nocov <- function(dat) {
    feols(
      formula_nocov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_nocov <- conjoint_all_m %>%
    split(.$party_n) %>%
    map(run_amce_nocov)

  capture.output(
    etable(models_by_party_n_nocov),
    file = file.path(output_dir, "amce_nocov_models.txt")
  )


  m_interaction <- feols(
    selected ~
      party_n_f *
      (
        policy_position +
          government_status +
          gdp_growth +
          nikkei +
          seats +
          cpi +
          unemployment
      ),
    data = conjoint_all_m,
    vcov = ~ ID
  )

  capture.output(
    summary(m_interaction),
    file = file.path(output_dir, "amce_interaction_model.txt")
  )


  tidy_fixest <- function(model) {
    ct <- as.data.frame(fixest::coeftable(model))
    ct$term <- rownames(ct)

    ct %>%
      as_tibble() %>%
      rename(
        estimate = Estimate,
        std.error = `Std. Error`,
        statistic = `t value`,
        p.value = `Pr(>|t|)`
      ) %>%
      mutate(
        conf.low = estimate - 1.96 * std.error,
        conf.high = estimate + 1.96 * std.error
      ) %>%
      select(
        term, estimate, std.error, statistic, p.value,
        conf.low, conf.high
      )
  }

  term_labels <- tribble(
    ~term, ~attribute, ~cue_type, ~label, ~order,

    "government_status与党",
    "与党/野党", "政党の手がかり", "与党", 1,

    "policy_position右派・保守的",
    "政策位置", "政党の手がかり", "右派・保守的", 2,

    "policy_position左派・革新的",
    "政策位置", "政党の手がかり", "左派・革新的", 3,

    "seats10~49",
    "議席数", "政党の手がかり", "議席数:10~49", 4,

    "seats50~99",
    "議席数", "政党の手がかり", "議席数:50~99", 5,

    "seats100~199",
    "議席数", "政党の手がかり", "議席数:100~199", 6,

    "seats200以上",
    "議席数", "政党の手がかり", "議席数:200以上", 7,

    "gdp_growthGDP成長率プラス1%",
    "GDP成長率", "経済の手がかり", "GDP:プラス1%", 8,

    "gdp_growthGDP成長率マイナス1%",
    "GDP成長率", "経済の手がかり", "GDP:マイナス1%", 9,

    "nikkei日経平均前月同期比プラス1000円",
    "日経平均", "経済の手がかり", "日経平均:プラス1000円", 10,

    "nikkei日経平均前月同期比マイナス1000円",
    "日経平均", "経済の手がかり", "日経平均:マイナス1000円", 11,

    "cpiCPI前期比プラス1ポイント",
    "CPI", "経済の手がかり", "CPI:プラス1ポイント", 12,

    "cpiCPI前期比マイナス1ポイント",
    "CPI", "経済の手がかり", "CPI:マイナス1ポイント", 13,

    "unemployment失業率前期比プラス1%",
    "失業率", "経済の手がかり", "失業率:プラス1%", 14,

    "unemployment失業率前期比マイナス1%",
    "失業率", "経済の手がかり", "失業率:マイナス1%", 15
  )

  attribute_order <- c(
    "与党/野党",
    "政策位置",
    "議席数",
    "GDP成長率",
    "日経平均",
    "CPI",
    "失業率"
  )

  label_order <- term_labels %>%
    arrange(order) %>%
    pull(label)

  make_amce_plot_df <- function(models) {
    imap_dfr(
      models,
      ~ tidy_fixest(.x) %>%
        mutate(party_n = as.character(.y))
    ) %>%
      left_join(term_labels, by = "term") %>%
      filter(!is.na(attribute)) %>%
      mutate(
        estimate_pp = estimate * 100,
        conf.low_pp = conf.low * 100,
        conf.high_pp = conf.high * 100,
        party_n = factor(
          party_n,
          levels = c("2", "3", "4", "5"),
          labels = c("2政党", "3政党", "4政党", "5政党")
        ),
        attribute = factor(attribute, levels = attribute_order),
        label = factor(label, levels = rev(label_order))
      )
  }

  amce_plot_nocov <- make_amce_plot_df(models_by_party_n_nocov)
  write_csv_safely(amce_plot_nocov, "amce_nocov_coefficients.csv")

  interaction_plot_df <- tidy_fixest(m_interaction) %>%
    filter(str_detect(term, "party_n_f[345]")) %>%
    mutate(
      party_n_code = str_extract(term, "party_n_f[345]"),
      party_n = str_remove(party_n_code, "party_n_f"),
      base_term = term %>%
        str_remove("party_n_f[345]:") %>%
        str_remove(":party_n_f[345]")
    ) %>%
    left_join(term_labels, by = c("base_term" = "term")) %>%
    filter(!is.na(attribute)) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      party_n_label = factor(
        party_n,
        levels = c("3", "4", "5"),
        labels = c("3政党", "4政党", "5政党")
      ),
      attribute = factor(attribute, levels = attribute_order),
      label = factor(label, levels = rev(label_order))
    )

  write_csv_safely(interaction_plot_df, "amce_interaction_coefficients.csv")


  recode_female_study2 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num == 2 ~ 1L,
      x_num == 1 ~ 0L,
      TRUE ~ NA_integer_
    )
  }

  recode_college_grad_study2 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num %in% c(4, 5) ~ 1L,
      x_num %in% c(1, 2, 3) ~ 0L,
      TRUE ~ NA_integer_
    )
  }

  recode_party_support_study2 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num == 1 ~ "自由民主党",
      x_num == 2 ~ "中道改革連合",
      x_num == 3 ~ "立憲民主党",
      x_num == 4 ~ "公明党",
      x_num == 5 ~ "日本維新の会",
      x_num == 6 ~ "国民民主党",
      x_num == 7 ~ "れいわ新選組",
      x_num == 8 ~ "日本共産党",
      x_num == 9 ~ "参政党",
      x_num == 10 ~ "日本保守党",
      x_num == 11 ~ "社会民主党",
      x_num == 12 ~ "チームみらい",
      x_num == 13 ~ "その他",
      x_num == 14 ~ "支持政党なし",
      x_num == 15 ~ "わからない",
      x_num == 16 ~ "答えたくない",
      TRUE ~ NA_character_
    )
  }

  gender_raw <- get_var(df, c("Q2.1", "Q2_1"))
  age_raw <- get_var(df, c("Q2.2_2", "Q2.2.2", "Q2_2_2"))
  education_raw <- get_var(df, c("Q2.3", "Q2_3"))
  income_gross_raw <- get_var(df, c("Q2.5_1", "Q2.5.1", "Q2_5_1"))
  income_net_raw <- get_var(df, c("Q2.5_2", "Q2.5.2", "Q2_5_2"))
  party_support_raw <- get_var(df, c("Q8.2", "Q8_2"))

  covar_id <- df %>%
    transmute(
      ID = as.character(ResponseId),
      female = recode_female_study2(gender_raw),
      age = as_num(age_raw),
      college_grad = recode_college_grad_study2(education_raw),
      income_gross = as_num(income_gross_raw),
      income_net = as_num(income_net_raw),
      income_gross_log = log1p(income_gross),
      income_net_log = log1p(income_net),
      party_support = recode_party_support_study2(party_support_raw),
      party_support_f = factor_miss(party_support)
    ) %>%
    semi_join(valid_ids %>% select(ID), by = "ID") %>%
    distinct(ID, .keep_all = TRUE)

  covar_id <- covar_id %>%
    mutate(
      age = if_else(age >= 18 & age <= 79, age, NA_real_)
    )

  age_imp_obj <- mean_impute(covar_id$age)
  income_gross_imp_obj <- mean_impute(covar_id$income_gross_log)

  covar_id <- covar_id %>%
    mutate(
      female_imp = if_else(is.na(female), 0L, female),
      female_miss = as.integer(is.na(female)),

      college_grad_imp = if_else(is.na(college_grad), 0L, college_grad),
      college_grad_miss = as.integer(is.na(college_grad)),

      age_imp = age_imp_obj$value,
      age_miss = age_imp_obj$miss,

      income_gross_log_imp = income_gross_imp_obj$value,
      income_gross_log_miss = income_gross_imp_obj$miss
    )

  covariate_missing_summary <- covar_id %>%
    summarise(
      n_ids = n_distinct(ID),
      female_missing = sum(is.na(female)),
      age_missing = sum(is.na(age)),
      college_grad_missing = sum(is.na(college_grad)),
      income_gross_missing = sum(is.na(income_gross_log)),
      party_support_missing = sum(is.na(party_support))
    )

  print(covariate_missing_summary)
  write_csv_safely(covar_id, "respondent_covariates.csv")
  write_csv_safely(covariate_missing_summary, "covariate_missing_summary.csv")


  conjoint_all_cov <- conjoint_all_m %>%
    left_join(covar_id, by = "ID")

  covariate_terms <- c(
    "female_imp",
    "female_miss",
    "age_imp",
    "age_miss",
    "college_grad_imp",
    "college_grad_miss",
    "income_gross_log_imp",
    "income_gross_log_miss",
    "party_support_f"
  )

  has_variation <- function(dat, v) {
    if (!v %in% names(dat)) return(FALSE)
    dplyr::n_distinct(dat[[v]], na.rm = TRUE) > 1
  }

  covariate_terms_use <- covariate_terms[
    map_lgl(covariate_terms, ~ has_variation(conjoint_all_cov, .x))
  ]

  formula_cov <- as.formula(
    paste(
      "selected ~",
      paste(c(attr_terms, covariate_terms_use), collapse = " + ")
    )
  )

  run_amce_cov <- function(dat) {
    feols(
      formula_cov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_cov <- conjoint_all_cov %>%
    split(.$party_n) %>%
    map(run_amce_cov)

  capture.output(
    etable(
      models_by_party_n_nocov,
      models_by_party_n_cov,
      headers = c(
        rep("共変量なし", length(models_by_party_n_nocov)),
        rep("共変量あり", length(models_by_party_n_cov))
      )
    ),
    file = file.path(output_dir, "amce_nocov_and_cov_models.txt")
  )

  amce_plot_cov <- make_amce_plot_df(models_by_party_n_cov)
  write_csv_safely(amce_plot_cov, "amce_cov_coefficients.csv")


  study_label <- "実験2(2026年)"

  term_labels_facet <- term_labels %>%
    mutate(
      attribute_facet = attribute
    )

  attribute_order_facet <- c(
    "与党/野党",
    "政策位置",
    "議席数",
    "GDP成長率",
    "日経平均",
    "CPI",
    "失業率"
  )

  make_amce_facet_df <- function(models) {
    imap_dfr(
      models,
      ~ tidy_fixest(.x) %>%
        mutate(party_n = as.character(.y))
    ) %>%
      left_join(term_labels_facet, by = "term") %>%
      filter(!is.na(attribute_facet)) %>%
      mutate(
        estimate_pp = estimate * 100,
        conf.low_pp = conf.low * 100,
        conf.high_pp = conf.high * 100,
        party_n = factor(
          party_n,
          levels = c("2", "3", "4", "5"),
          labels = c("2政党", "3政党", "4政党", "5政党")
        ),
        attribute_facet = factor(
          attribute_facet,
          levels = attribute_order_facet
        ),
        label = factor(
          label,
          levels = rev(label_order)
        )
      )
  }

  amce_plot_df_cov_facet <- make_amce_facet_df(models_by_party_n_cov)
  amce_plot_df_nocov_facet <- make_amce_facet_df(models_by_party_n_nocov)

  write_csv_safely(
    amce_plot_df_cov_facet,
    "amce_cov_facet_coefficients.csv"
  )

  write_csv_safely(
    amce_plot_df_nocov_facet,
    "amce_nocov_facet_coefficients.csv"
  )


  p_amce_cov_facet <- ggplot(
    amce_plot_df_cov_facet,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute_facet ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-12, 12, by = 2)
    ) +
    scale_shape_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = "Yu Gothic"
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_amce_cov_facet)

  save_plot(
    "amce_cov_facet_model.png",
    p_amce_cov_facet,
    width = 10.5,
    height = 8.5
  )

  p_amce_cov_main <- p_amce_cov_facet


  make_heatmap_df <- function(amce_plot_df) {
    heat_df <- amce_plot_df %>%
      mutate(
        abs_amce = abs(estimate_pp),
        cue_type_code = case_when(
          cue_type == "政党の手がかり" ~ "party",
          cue_type == "経済の手がかり" ~ "economy",
          TRUE ~ "other"
        )
      ) %>%
      group_by(party_n) %>%
      mutate(
        rank_within_party = min_rank(desc(abs_amce)),
        n_in_col = n(),
        rank_score = if_else(
          n_in_col == 1,
          1,
          1 - (rank_within_party - 1) / (n_in_col - 1)
        )
      ) %>%
      ungroup()

    row_order_df <- heat_df %>%
      group_by(label, cue_type_code) %>%
      summarise(
        mean_abs_amce = mean(abs_amce, na.rm = TRUE),
        .groups = "drop"
      ) %>%
      arrange(desc(mean_abs_amce))

    row_levels <- as.character(row_order_df$label)

    heat_df <- heat_df %>%
      mutate(
        label = factor(
          as.character(label),
          levels = rev(row_levels)
        )
      )

    label_color_map <- row_order_df %>%
      mutate(
        label_markdown = case_when(
          cue_type_code == "party" ~
            paste0(
              "<span style='color:#111111;'>",
              label,
              "</span>"
            ),
          cue_type_code == "economy" ~
            paste0(
              "<span style='color:#8A8A8A;'>",
              label,
              "</span>"
            ),
          TRUE ~ as.character(label)
        )
      )

    label_markdown_vec <- setNames(
      label_color_map$label_markdown,
      as.character(label_color_map$label)
    )

    list(
      heat_df = heat_df,
      label_markdown_vec = label_markdown_vec
    )
  }

  plot_amce_heatmap <- function(
      heat_df,
      label_markdown_vec,
      with_rank = TRUE,
      title_text = NULL) {

    if (with_rank) {
      heat_df <- heat_df %>%
        mutate(
          cell_label = paste0(
            sprintf("%.1f", estimate_pp),
            "\n(",
            rank_within_party,
            "位)"
          )
        )

      text_size <- 3.0
      lineheight <- 0.9
    } else {
      heat_df <- heat_df %>%
        mutate(
          cell_label = sprintf("%.1f", estimate_pp)
        )

      text_size <- 3.4
      lineheight <- 1.0
    }

    ggplot(
      heat_df,
      aes(
        x = party_n,
        y = label,
        fill = rank_score
      )
    ) +
      geom_tile(
        color = "white",
        linewidth = 0.7
      ) +
      geom_text(
        aes(label = cell_label),
        size = text_size,
        fontface = "bold",
        color = "black",
        lineheight = lineheight
      ) +
      scale_y_discrete(
        labels = label_markdown_vec
      ) +
      scale_fill_gradient(
        low = "grey95",
        high = "grey15",
        limits = c(0, 1),
        breaks = c(0, 0.25, 0.50, 0.75, 1.00),
        labels = c("低", "", "", "", "高"),
        name = "列内順位\n(濃いほど高位)"
      ) +
      labs(
        title = title_text,
        x = "政党数選択肢",
        y = NULL
      ) +
      theme_bw(base_size = 12) +
      theme(
        legend.position = "right",
        panel.grid = element_blank(),
        plot.title = element_text(face = "bold"),
        axis.text.x = element_text(size = 10),
        axis.text.y = ggtext::element_markdown(size = 9),
        axis.title.y = element_blank()
      )
  }

  heatmap_input <- make_heatmap_df(amce_plot_cov)

  p_heat_amce_mixed <- plot_amce_heatmap(
    heatmap_input$heat_df,
    heatmap_input$label_markdown_vec,
    with_rank = FALSE,
    title_text = NULL
  )

  print(p_heat_amce_mixed)

  save_plot(
    "amce_heatmap_mixed_rank_colored_labels.png",
    p_heat_amce_mixed,
    width = 8.8,
    height = 8.8
  )

  p_heat_amce_mixed_ranklabel <- plot_amce_heatmap(
    heatmap_input$heat_df,
    heatmap_input$label_markdown_vec,
    with_rank = TRUE,
    title_text = NULL
  )

  print(p_heat_amce_mixed_ranklabel)

  save_plot(
    "amce_heatmap_mixed_rank_colored_labels_withrank.png",
    p_heat_amce_mixed_ranklabel,
    width = 8.8,
    height = 8.8
  )

  p_heat_amce <- p_heat_amce_mixed
  p_heat_amce_rank <- p_heat_amce_mixed_ranklabel


  p_amce_facet_nocov <- ggplot(
    amce_plot_df_nocov_facet,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute_facet ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-12, 12, by = 2)
    ) +
    scale_shape_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "政党数選択肢",
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(base_size = 12) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_amce_facet_nocov)

  save_plot(
    "amce_facet_nocov.png",
    p_amce_facet_nocov,
    width = 10.5,
    height = 9
  )

  p_amce_nocov_appendix <- p_amce_facet_nocov


  p_interaction <- ggplot(
    interaction_plot_df,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n_label,
      linetype = party_n_label,
      group = party_n_label
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(width = 0.65),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.65),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) paste0(x, " pp"),
      breaks = seq(-8, 8, by = 2)
    ) +
    scale_shape_manual(
      name = "2政党の場合との比較",
      values = c(
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      name = "2政党の場合との比較",
      values = c(
        "3政党" = "dashed",
        "4政党" = "dotted",
        "5政党" = "dotdash"
      )
    ) +
    labs(
      x = "2政党条件との差",
      y = NULL
    ) +
    theme_bw(base_size = 12) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 15
      ),
      plot.subtitle = element_text(size = 11),
      legend.position = "top",
      legend.title = element_text(face = "bold"),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(size = 9),
      axis.title.x = element_text(face = "bold")
    )

  print(p_interaction)

  save_plot(
    "amce_interaction_difference_from_2party.png",
    p_interaction,
    width = 10.5,
    height = 9
  )


  conjoint_clogit <- conjoint_all_m %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),
      task_id = factor(task_id),
      policy_position = relevel_if_present(
        policy_position,
        "中道"
      ),
      government_status = relevel_if_present(
        government_status,
        "野党"
      ),
      gdp_growth = relevel_if_present(
        gdp_growth,
        "GDP成長率±0%"
      ),
      nikkei = relevel_if_present(
        nikkei,
        "日経平均前月同期比変わらず"
      ),
      seats = relevel_if_present(
        seats,
        "10以下"
      ),
      cpi = relevel_if_present(
        cpi,
        "CPI前期比±0ポイント"
      ),
      unemployment = relevel_if_present(
        unemployment,
        "失業率前期比±0%"
      )
    )

  formula_clogit_nocov <- as.formula(
    paste0(
      "selected ~ ",
      paste(attr_terms, collapse = " + "),
      " + strata(task_id) + cluster(ID)"
    )
  )

  run_clogit_nocov <- function(dat) {
    survival::clogit(
      formula_clogit_nocov,
      data = dat,
      method = "efron"
    )
  }

  models_clogit_nocov <- conjoint_clogit %>%
    split(.$party_n) %>%
    map(run_clogit_nocov)

  capture.output(
    lapply(models_clogit_nocov, summary),
    file = file.path(
      output_dir,
      "conditional_logit_models.txt"
    )
  )

  tidy_clogit <- function(model) {
    s <- summary(model)
    ct <- as.data.frame(s$coefficients)
    ct$term <- rownames(ct)

    se_col <- if ("robust se" %in% names(ct)) {
      "robust se"
    } else if ("se(coef)" %in% names(ct)) {
      "se(coef)"
    } else {
      stop("Check clogit")
    }

    p_col <- if ("Pr(>|z|)" %in% names(ct)) {
      "Pr(>|z|)"
    } else if ("Pr(>|t|)" %in% names(ct)) {
      "Pr(>|t|)"
    } else {
      NA_character_
    }

    ct %>%
      as_tibble() %>%
      transmute(
        term = term,
        estimate = coef,
        std.error = .data[[se_col]],
        p.value = if (!is.na(p_col)) {
          .data[[p_col]]
        } else {
          NA_real_
        },
        conf.low = estimate - 1.96 * std.error,
        conf.high = estimate + 1.96 * std.error,
        odds_ratio = exp(estimate),
        odds_ratio_low = exp(conf.low),
        odds_ratio_high = exp(conf.high)
      )
  }

  clogit_plot_df <- imap_dfr(
    models_clogit_nocov,
    ~ tidy_clogit(.x) %>%
      mutate(party_n = as.character(.y))
  ) %>%
    left_join(term_labels, by = "term") %>%
    filter(!is.na(attribute)) %>%
    mutate(
      party_n = factor(
        party_n,
        levels = c("2", "3", "4", "5"),
        labels = c("2政党", "3政党", "4政党", "5政党")
      ),
      label = factor(
        label,
        levels = rev(label_order)
      )
    )

  write_csv_safely(
    clogit_plot_df,
    "conditional_logit_coefficients.csv"
  )


  p_clogit_or <- ggplot(
    clogit_plot_df,
    aes(
      x = odds_ratio,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 1,
      linetype = "dashed",
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = odds_ratio_low,
        xmax = odds_ratio_high
      ),
      position = position_dodge(width = 0.72),
      height = 0.15,
      linewidth = 0.45,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(width = 0.72),
      size = 2.4,
      stroke = 0.7,
      color = "black"
    ) +
    scale_x_log10(
      breaks = c(
        0.6,
        0.8,
        1.0,
        1.25,
        1.5,
        2.0
      ),
      labels = c(
        "0.6",
        "0.8",
        "1.0",
        "1.25",
        "1.5",
        "2.0"
      )
    ) +
    scale_shape_manual(
      values = c(
        "2政党" = 16,
        "3政党" = 17,
        "4政党" = 15,
        "5政党" = 1
      )
    ) +
    scale_linetype_manual(
      values = c(
        "2政党" = "solid",
        "3政党" = "dashed",
        "4政党" = "dotdash",
        "5政党" = "twodash"
      )
    ) +
    labs(
      x = "オッズ比",
      y = NULL,
      shape = "政党数選択肢",
      linetype = "政党数選択肢"
    ) +
    theme_bw(base_size = 12) +
    theme(
      legend.position = "bottom",
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      plot.title = element_text(face = "bold"),
      axis.text.y = element_text(size = 9)
    )

  print(p_clogit_or)

  save_plot(
    "clogit_oddsratio_nocov.png",
    p_clogit_or,
    width = 10.5,
    height = 8.5
  )


  relative_cue_map <- c(
    policy_position = "party",
    government_status = "party",
    seats = "party",
    gdp_growth = "economic",
    nikkei = "economic",
    cpi = "economic",
    unemployment = "economic"
  )

  mean_absolute_pairwise_difference <- function(x) {
    x <- x[is.finite(x)]

    if (length(x) < 2) {
      return(NA_real_)
    }

    pairwise_differences <- combn(
      x,
      2,
      FUN = function(z) abs(z[1] - z[2])
    )

    mean(pairwise_differences)
  }

  linear_slope <- function(y, x) {
    keep <- is.finite(y) & is.finite(x)
    y <- y[keep]
    x <- x[keep]

    if (length(y) < 2 || length(unique(x)) < 2) {
      return(NA_real_)
    }

    unname(coef(lm(y ~ x))[2])
  }

  bootstrap_two_sided_p <- function(x) {
    x <- x[is.finite(x)]
    B_valid <- length(x)

    if (B_valid == 0) {
      return(NA_real_)
    }

    p_lower <- (1 + sum(x <= 0)) / (B_valid + 1)
    p_upper <- (1 + sum(x >= 0)) / (B_valid + 1)

    min(1, 2 * min(p_lower, p_upper))
  }

  safe_quantile <- function(x, probability) {
    x <- x[is.finite(x)]

    if (length(x) == 0) {
      return(NA_real_)
    }

    unname(
      quantile(
        x,
        probs = probability,
        type = 6,
        na.rm = TRUE
      )
    )
  }

  prepare_relative_cue_analysis <- function(data, cue_map) {
    attributes <- names(cue_map)

    required_columns <- c(
      "ID",
      "party_n",
      "selected",
      attributes
    )

    missing_columns <- setdiff(
      required_columns,
      names(data)
    )

    if (length(missing_columns) > 0) {
      stop("Check relative weight")
    }

    if (!all(unname(cue_map) %in% c("party", "economic"))) {
      stop("Check relative weight")
    }

    analysis_data <- data %>%
      select(
        ID,
        party_n,
        selected,
        all_of(attributes)
      ) %>%
      mutate(
        ID = as.character(ID),
        party_n = as.integer(as.character(party_n)),
        selected = as.integer(selected),
        across(
          all_of(attributes),
          as.character
        )
      ) %>%
      filter(
        !is.na(ID),
        party_n %in% 2:5,
        selected %in% c(0L, 1L)
      )

    observed_conditions <- sort(
      unique(analysis_data$party_n)
    )

    if (!identical(observed_conditions, 2:5)) {
      stop("Check")
    }

    long_data <- analysis_data %>%
      pivot_longer(
        cols = all_of(attributes),
        names_to = "attribute",
        values_to = "level"
      ) %>%
      filter(
        !is.na(level),
        level != ""
      )

    expected_cells <- long_data %>%
      distinct(
        attribute,
        level
      ) %>%
      mutate(
        attribute_order = match(
          attribute,
          attributes
        )
      ) %>%
      arrange(
        attribute_order,
        attribute,
        level
      ) %>%
      select(-attribute_order) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    respondent_cell <- long_data %>%
      group_by(
        party_n,
        ID,
        attribute,
        level
      ) %>%
      summarise(
        y_sum = sum(selected),
        n_obs = n(),
        .groups = "drop"
      ) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    condition_objects <- lapply(
      2:5,
      function(n_value) {
        condition_data <- respondent_cell %>%
          filter(
            party_n == n_value
          )

        id_values <- sort(
          unique(condition_data$ID)
        )
        n_ids <- length(id_values)
        n_cells <- nrow(expected_cells)

        if (n_ids == 0) {
          stop("Check")
        }

        y_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        n_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        row_index <- match(
          condition_data$ID,
          id_values
        )
        column_index <- match(
          condition_data$cell_key,
          expected_cells$cell_key
        )

        y_matrix[cbind(row_index, column_index)] <-
          condition_data$y_sum
        n_matrix[cbind(row_index, column_index)] <-
          condition_data$n_obs

        if (any(colSums(n_matrix) == 0)) {
          missing_cells <- expected_cells$cell_key[
            colSums(n_matrix) == 0
          ]

          stop("Check attributes")
        }

        list(
          party_n = n_value,
          ids = id_values,
          cell_info = expected_cells,
          y_matrix = y_matrix,
          n_matrix = n_matrix
        )
      }
    )

    names(condition_objects) <- as.character(2:5)

    list(
      cue_map = cue_map,
      attributes = attributes,
      conditions = condition_objects
    )
  }

  estimate_relative_cue_indices <- function(
      prepared,
      cluster_weights = NULL
  ) {
    condition_results <- lapply(
      names(prepared$conditions),
      function(condition_name) {
        object <- prepared$conditions[[condition_name]]

        if (is.null(cluster_weights)) {
          weights <- rep(
            1,
            length(object$ids)
          )
        } else {
          weights <- cluster_weights[[condition_name]]
        }

        if (length(weights) != length(object$ids)) {
          stop("Check")
        }

        numerator <- as.numeric(
          crossprod(
            weights,
            object$y_matrix
          )
        )

        denominator <- as.numeric(
          crossprod(
            weights,
            object$n_matrix
          )
        )

        if (any(denominator <= 0)) {
          stop("Check attributes")
        }

        marginal_means <- numerator / denominator

        mm_table <- object$cell_info %>%
          transmute(
            party_n = object$party_n,
            attribute,
            level,
            marginal_mean = marginal_means
          )

        attribute_table <- mm_table %>%
          group_by(
            party_n,
            attribute
          ) %>%
          summarise(
            importance_pairwise =
              mean_absolute_pairwise_difference(
                marginal_mean
              ),
            n_levels = n(),
            .groups = "drop"
          ) %>%
          mutate(
            cue_family = unname(
              prepared$cue_map[attribute]
            ),
            baseline_selection_probability = 1 / party_n,
            importance_pairwise_adjusted =
              importance_pairwise /
                baseline_selection_probability
          )

        cue_table_long <- attribute_table %>%
          group_by(
            party_n,
            cue_family
          ) %>%
          summarise(
            importance_pairwise = mean(
              importance_pairwise,
              na.rm = TRUE
            ),
            importance_pairwise_adjusted = mean(
              importance_pairwise_adjusted,
              na.rm = TRUE
            ),
            .groups = "drop"
          )

        party_table <- cue_table_long %>%
          filter(
            cue_family == "party"
          ) %>%
          transmute(
            party_n,
            party_importance_pairwise =
              importance_pairwise,
            party_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        economic_table <- cue_table_long %>%
          filter(
            cue_family == "economic"
          ) %>%
          transmute(
            party_n,
            economic_importance_pairwise =
              importance_pairwise,
            economic_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        cue_table <- full_join(
          party_table,
          economic_table,
          by = "party_n"
        ) %>%
          mutate(
            baseline_selection_probability = 1 / party_n,

            total_importance_pairwise =
              party_importance_pairwise +
              economic_importance_pairwise,

            total_importance_pairwise_adjusted =
              party_importance_pairwise_adjusted +
              economic_importance_pairwise_adjusted,

            relative_party_weight_pairwise = if_else(
              total_importance_pairwise > 0,
              party_importance_pairwise /
                total_importance_pairwise,
              NA_real_
            ),

            relative_economic_weight_pairwise =
              1 - relative_party_weight_pairwise,

            relative_party_weight_pairwise_adjusted = if_else(
              total_importance_pairwise_adjusted > 0,
              party_importance_pairwise_adjusted /
                total_importance_pairwise_adjusted,
              NA_real_
            ),

            relative_economic_weight_pairwise_adjusted =
              1 - relative_party_weight_pairwise_adjusted,

            adjustment_identity_difference =
              relative_party_weight_pairwise_adjusted -
                relative_party_weight_pairwise
          )

        if (
          any(
            abs(cue_table$adjustment_identity_difference) > 1e-10,
            na.rm = TRUE
          )
        ) {
          stop("Check relative weight")
        }

        list(
          marginal_means = mm_table,
          attribute_importance = attribute_table,
          cue_importance = cue_table
        )
      }
    )

    list(
      marginal_means = bind_rows(
        lapply(
          condition_results,
          function(x) x$marginal_means
        )
      ),
      attribute_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$attribute_importance
        )
      ),
      cue_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$cue_importance
        )
      ) %>%
        arrange(party_n)
    )
  }

  estimate_relative_cue_slopes <- function(cue_importance) {
    cue_importance <- cue_importance %>%
      arrange(party_n)

    if (!identical(cue_importance$party_n, 2:5)) {
      stop("Check relative weight")
    }

    x <- cue_importance$party_n

    c(
      relative_party_weight_pairwise =
        linear_slope(
          cue_importance$relative_party_weight_pairwise,
          x
        ),

      party_importance_pairwise =
        linear_slope(
          cue_importance$party_importance_pairwise,
          x
        ),

      economic_importance_pairwise =
        linear_slope(
          cue_importance$economic_importance_pairwise,
          x
        ),

      party_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$party_importance_pairwise_adjusted,
          x
        ),

      economic_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$economic_importance_pairwise_adjusted,
          x
        )
    )
  }

  run_relative_cue_bootstrap <- function(
      prepared,
      B,
      seed,
      progress_every = 100
  ) {
    set.seed(seed)

    condition_results <- vector(
      "list",
      B
    )

    slope_names <- c(
      "relative_party_weight_pairwise",
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted"
    )

    slope_matrix <- matrix(
      NA_real_,
      nrow = B,
      ncol = length(slope_names),
      dimnames = list(
        NULL,
        slope_names
      )
    )

    for (b in seq_len(B)) {
      cluster_weights <- lapply(
        prepared$conditions,
        function(object) {
          n_ids <- length(object$ids)

          sampled_positions <- sample.int(
            n = n_ids,
            size = n_ids,
            replace = TRUE
          )

          tabulate(
            sampled_positions,
            nbins = n_ids
          )
        }
      )

      bootstrap_estimates <- estimate_relative_cue_indices(
        prepared = prepared,
        cluster_weights = cluster_weights
      )

      condition_results[[b]] <-
        bootstrap_estimates$cue_importance %>%
        select(
          party_n,
          party_importance_pairwise,
          economic_importance_pairwise,
          party_importance_pairwise_adjusted,
          economic_importance_pairwise_adjusted,
          relative_party_weight_pairwise
        ) %>%
        mutate(
          bootstrap_replication = b,
          .before = 1
        )

      slope_matrix[b, ] <- estimate_relative_cue_slopes(
        bootstrap_estimates$cue_importance
      )

      if (
        progress_every > 0 &&
        (b %% progress_every == 0 || b == B)
      ) {
        message("Bootstrap: ", b, "/", B)
      }
    }

    list(
      condition_estimates = bind_rows(
        condition_results
      ),
      slopes = as_tibble(
        slope_matrix
      ) %>%
        mutate(
          bootstrap_replication = row_number(),
          .before = 1
        )
    )
  }

  summarise_condition_intervals <- function(
      observed_cue_importance,
      bootstrap_condition_results
  ) {
    statistics <- c(
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted",
      "relative_party_weight_pairwise"
    )

    observed_long <- observed_cue_importance %>%
      select(
        party_n,
        all_of(statistics)
      ) %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "estimate"
      )

    bootstrap_long <- bootstrap_condition_results %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "value"
      ) %>%
      group_by(
        party_n,
        statistic
      ) %>%
      summarise(
        conf_low = safe_quantile(
          value,
          0.025
        ),
        conf_high = safe_quantile(
          value,
          0.975
        ),
        .groups = "drop"
      )

    observed_long %>%
      left_join(
        bootstrap_long,
        by = c(
          "party_n",
          "statistic"
        )
      )
  }

  summarise_slope_inference <- function(
      observed_slopes,
      bootstrap_slopes
  ) {
    statistic_names <- names(observed_slopes)

    map_dfr(
      statistic_names,
      function(statistic_name) {
        bootstrap_values <- bootstrap_slopes[[statistic_name]]
        bootstrap_values <- bootstrap_values[
          is.finite(bootstrap_values)
        ]

        expected_direction <- case_when(
          statistic_name ==
            "economic_importance_pairwise" ~ "negative",
          statistic_name %in% c(
            "party_importance_pairwise",
            "relative_party_weight_pairwise",
            "party_importance_pairwise_adjusted"
          ) ~ "positive",
          TRUE ~ "none"
        )

        analysis_role <- case_when(
          statistic_name %in% c(
            "party_importance_pairwise_adjusted",
            "economic_importance_pairwise_adjusted"
          ) ~ "exploratory_choice_set_adjusted",
          statistic_name == "relative_party_weight_pairwise" ~
            "derived_relative_share",
          TRUE ~ "manuscript_primary_unadjusted"
        )

        estimate <- unname(
          observed_slopes[[statistic_name]]
        )

        tibble(
          study = "Study 2",
          statistic = statistic_name,
          estimate = estimate,
          conf_low = safe_quantile(
            bootstrap_values,
            0.025
          ),
          conf_high = safe_quantile(
            bootstrap_values,
            0.975
          ),
          p_value_two_sided =
            bootstrap_two_sided_p(
              bootstrap_values
            ),
          expected_direction = expected_direction,
          analysis_role = analysis_role,
          estimate_in_expected_direction = case_when(
            expected_direction == "positive" ~ estimate > 0,
            expected_direction == "negative" ~ estimate < 0,
            TRUE ~ NA
          )
        )
      }
    )
  }

  relative_cue_prepared <- prepare_relative_cue_analysis(
    data = conjoint_all_m,
    cue_map = relative_cue_map
  )

  relative_cue_observed <- estimate_relative_cue_indices(
    prepared = relative_cue_prepared
  )

  relative_cue_observed_slopes <- estimate_relative_cue_slopes(
    relative_cue_observed$cue_importance
  )

  write_csv_safely(
    relative_cue_observed$marginal_means,
    "study2_relative_cue_marginal_means.csv"
  )

  write_csv_safely(
    relative_cue_observed$attribute_importance,
    "study2_relative_cue_attribute_importance.csv"
  )

  write_csv_safely(
    relative_cue_observed$cue_importance,
    "study2_relative_cue_importance_and_weight.csv"
  )

  relative_condition_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study2_relative_cue_condition_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  relative_slope_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study2_relative_cue_slope_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  use_saved_relative_bootstrap <-
    !rerun_relative_cue_bootstrap &&
    file.exists(relative_condition_bootstrap_file) &&
    file.exists(relative_slope_bootstrap_file)

  if (use_saved_relative_bootstrap) {
    message("Bootstrap cache")

    relative_cue_condition_bootstrap <- readr::read_csv(
      relative_condition_bootstrap_file,
      show_col_types = FALSE
    )

    relative_cue_slope_bootstrap <- readr::read_csv(
      relative_slope_bootstrap_file,
      show_col_types = FALSE
    )

    saved_B_condition <- n_distinct(
      relative_cue_condition_bootstrap$bootstrap_replication
    )
    saved_B_slope <- n_distinct(
      relative_cue_slope_bootstrap$bootstrap_replication
    )

    if (
      saved_B_condition != relative_cue_bootstrap_B ||
      saved_B_slope != relative_cue_bootstrap_B
    ) {
      message("Bootstrap cache")
      use_saved_relative_bootstrap <- FALSE
    }
  }

  if (!use_saved_relative_bootstrap) {
    relative_cue_bootstrap <- run_relative_cue_bootstrap(
      prepared = relative_cue_prepared,
      B = relative_cue_bootstrap_B,
      seed = relative_cue_bootstrap_seed,
      progress_every = relative_cue_bootstrap_progress_every
    )

    relative_cue_condition_bootstrap <-
      relative_cue_bootstrap$condition_estimates

    relative_cue_slope_bootstrap <-
      relative_cue_bootstrap$slopes

    readr::write_csv(
      relative_cue_condition_bootstrap,
      relative_condition_bootstrap_file
    )

    readr::write_csv(
      relative_cue_slope_bootstrap,
      relative_slope_bootstrap_file
    )
  }

  relative_cue_condition_intervals <- summarise_condition_intervals(
    observed_cue_importance =
      relative_cue_observed$cue_importance,
    bootstrap_condition_results =
      relative_cue_condition_bootstrap
  )

  relative_cue_slope_inference <- summarise_slope_inference(
    observed_slopes =
      relative_cue_observed_slopes,
    bootstrap_slopes =
      relative_cue_slope_bootstrap
  )

  write_csv_safely(
    relative_cue_condition_intervals,
    "study2_relative_cue_condition_intervals.csv"
  )

  write_csv_safely(
    relative_cue_slope_inference,
    "study2_relative_cue_slope_inference.csv"
  )

  relative_cue_primary_result <- relative_cue_slope_inference %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    )

  cat("\nStudy 2:相対比重の線形傾向\n")
  print(relative_cue_primary_result)


  relative_x_offset <- 0.075

  relative_panel_a_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise",
        "economic_importance_pairwise"
      )
    ) %>%
    mutate(
      cue_family = recode(
        statistic,
        party_importance_pairwise = "政党手がかり",
        economic_importance_pairwise = "経済手がかり"
      ),
      cue_family = factor(
        cue_family,
        levels = c(
          "政党手がかり",
          "経済手がかり"
        )
      ),
      x_plot = case_when(
        cue_family == "政党手がかり" ~
          party_n + relative_x_offset,
        cue_family == "経済手がかり" ~
          party_n - relative_x_offset,
        TRUE ~ as.numeric(party_n)
      ),
      value_label = sprintf(
        "%.3f",
        estimate
      )
    )

  relative_panel_b_data <- relative_cue_condition_intervals %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    ) %>%
    mutate(
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_adjusted_label_map <- relative_panel_a_data %>%
    distinct(
      statistic,
      cue_family
    ) %>%
    mutate(
      statistic = paste0(
        statistic,
        "_adjusted"
      ),
      cue_family = as.character(
        cue_family
      )
    )

  relative_panel_adjusted_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise_adjusted",
        "economic_importance_pairwise_adjusted"
      )
    ) %>%
    left_join(
      relative_adjusted_label_map,
      by = "statistic"
    ) %>%
    mutate(
      cue_family = factor(
        cue_family,
        levels = levels(
          relative_panel_a_data$cue_family
        )
      ),
      x_plot = if_else(
        as.integer(cue_family) == 1L,
        party_n + relative_x_offset,
        party_n - relative_x_offset
      ),
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_condition_suffix <- if (
    "政党名手がかり" %in%
      levels(relative_panel_a_data$cue_family)
  ) {
    "選択肢"
  } else {
    "政党"
  }

  relative_condition_axis_title <- if (
    relative_condition_suffix == "選択肢"
  ) {
    "政治経済状況の選択肢数"
  } else {
    "政党選択肢数"
  }

  relative_figure_font_family <- if (
    .Platform$OS.type == "windows"
  ) {
    "Yu Gothic"
  } else {
    "sans"
  }

  relative_theme_japanese_bw <- theme_bw(
    base_size = 12,
    base_family = relative_figure_font_family
  ) +
    theme(
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(
        linewidth = 0.30,
        color = "grey88"
      ),
      panel.border = element_rect(
        linewidth = 0.65,
        color = "black"
      ),
      axis.text = element_text(
        color = "black"
      ),
      axis.title = element_text(
        color = "black"
      ),
      plot.title = element_text(
        size = 12.5,
        face = "bold",
        hjust = 0
      ),
      plot.subtitle = element_text(
        size = 9.5,
        hjust = 0,
        margin = margin(
          b = 8
        )
      ),
      legend.position = "top",
      legend.justification = "center",
      legend.key.width = grid::unit(
        1.25,
        "cm"
      ),
      plot.margin = margin(
        8,
        10,
        8,
        8
      )
    )

  relative_panel_a <- ggplot(
    relative_panel_a_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = c(
        "政党手がかり" = "solid",
        "経済手がかり" = "dashed"
      )
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "政党"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_number(
        accuracy = 0.005
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:両手がかりの絶対的重要度",
      subtitle = "",
      x = "政党選択肢数",
      y = "手がかり重要度",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_adjusted_linetypes <- setNames(
    c(
      "solid",
      "dashed"
    ),
    levels(
      relative_panel_adjusted_data$cue_family
    )
  )

  relative_panel_adjusted <- ggplot(
    relative_panel_adjusted_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = relative_adjusted_linetypes
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        relative_condition_suffix
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:選択肢数調整済み重要度",
      subtitle =
        "未調整重要度 ÷ 平均選択確率(1/選択肢数)",
      x = relative_condition_axis_title,
      y = "平均選択確率に対する水準間差",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_b_range <- range(
    c(
      relative_panel_b_data$conf_low,
      relative_panel_b_data$conf_high,
      0.5
    ),
    na.rm = TRUE
  )

  relative_b_padding <- max(
    0.025,
    0.10 * diff(relative_b_range)
  )

  relative_b_lower <- max(
    0,
    floor(
      20 *
        (relative_b_range[1] - relative_b_padding)
    ) / 20
  )

  relative_b_upper <- min(
    1,
    ceiling(
      20 *
        (relative_b_range[2] + relative_b_padding)
    ) / 20
  )

  if (relative_b_lower >= relative_b_upper) {
    relative_b_lower <- max(
      0,
      relative_b_lower - 0.05
    )
    relative_b_upper <- min(
      1,
      relative_b_upper + 0.05
    )
  }

  relative_panel_b <- ggplot(
    relative_panel_b_data,
    aes(
      x = party_n,
      y = estimate
    )
  ) +
    geom_hline(
      yintercept = 0.5,
      linetype = "dashed",
      linewidth = 0.55,
      color = "black"
    ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "政党"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      breaks = seq(
        relative_b_lower,
        relative_b_upper,
        by = 0.05
      ),
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.05,
          0.08
        )
      )
    ) +
    coord_cartesian(
      ylim = c(
        relative_b_lower,
        relative_b_upper
      )
    ) +
    labs(
      title = "B:相対的な政党手がかりの比重",
      subtitle =
        "政党手がかり重要度 ÷(政党手がかり重要度+経済手がかり重要度)",
      x = "政党選択肢数",
      y = "相対的な政党手がかり比重"
    ) +
    relative_theme_japanese_bw +
    theme(
      legend.position = "none"
    )

  relative_panel_c <- relative_panel_b +
    labs(
      title = paste0(
        "B:相対的な",
        levels(relative_panel_a_data$cue_family)[1],
        "の比重"
      )
    )

  figure_relative_weight_jp <- (
    relative_panel_a |
      relative_panel_b
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_jp
  )

  save_plot(
    "fig_study2_relative_cue_weight_jp_bw.png",
    figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      "fig_study2_relative_cue_weight_jp_bw.pdf"
    ),
    plot = figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  figure_relative_weight_adjusted_jp <- (
    relative_panel_adjusted |
      relative_panel_c
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_adjusted_jp
  )

  relative_adjusted_figure_stub <- paste0(
    "fig_study",
    stringr::str_extract(
      study_label,
      "[123]"
    ),
    "_relative_cue_weight_choice_set_adjusted_jp_bw"
  )

  save_plot(
    paste0(
      relative_adjusted_figure_stub,
      ".png"
    ),
    figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      paste0(
        relative_adjusted_figure_stub,
        ".pdf"
      )
    ),
    plot = figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  relative_cue_results <- list(
    prepared = relative_cue_prepared,
    marginal_means =
      relative_cue_observed$marginal_means,
    attribute_importance =
      relative_cue_observed$attribute_importance,
    cue_importance =
      relative_cue_observed$cue_importance,
    observed_slopes =
      relative_cue_observed_slopes,
    condition_bootstrap =
      relative_cue_condition_bootstrap,
    slope_bootstrap =
      relative_cue_slope_bootstrap,
    condition_intervals =
      relative_cue_condition_intervals,
    slope_inference =
      relative_cue_slope_inference,
    primary_result =
      relative_cue_primary_result,
    plots = list(
      absolute_importance = relative_panel_a,
      choice_set_adjusted_importance =
        relative_panel_adjusted,
      relative_party_weight = relative_panel_b,
      relative_party_weight_panel_c =
        relative_panel_c,
      combined = figure_relative_weight_jp,
      combined_with_choice_set_adjustment =
        figure_relative_weight_adjusted_jp
    )
  )

  saveRDS(
    relative_cue_results,
    file = file.path(
      output_dir,
      "study2_relative_cue_results.rds"
    )
  )


  saveRDS(
    list(
      settings = list(
        require_initial_consent = require_initial_consent,
        require_final_consent = require_final_consent,
        require_attention_check = require_attention_check,
        require_manipulation_check = require_manipulation_check
      ),
      sample_flow = sample_flow,
      n_by_party = n_by_party,
      valid_ids = valid_ids,
      conjoint_all = conjoint_all,
      conjoint_all_m = conjoint_all_m,
      covar_id = covar_id,
      models_by_party_n_nocov = models_by_party_n_nocov,
      models_by_party_n_cov = models_by_party_n_cov,
      m_interaction = m_interaction,
      models_clogit_nocov = models_clogit_nocov,
      relative_cue = relative_cue_results,
      plots = list(
        amce_cov = p_amce_cov_main,
        amce_nocov = p_amce_nocov_appendix,
        interaction = p_interaction,
        heatmap = p_heat_amce,
        heatmap_rank = p_heat_amce_rank,
        clogit_odds_ratio = p_clogit_or,
        relative_cue_weight = figure_relative_weight_jp,
        relative_cue_weight_choice_set_adjusted =
          figure_relative_weight_adjusted_jp
      )
    ),
    file = file.path(output_dir, "study2_analysis_objects.rds")
  )

  capture.output(
    sessionInfo(),
    file = file.path(output_dir, "sessionInfo.txt")
  )

  cat("
Done: ", normalizePath(output_dir), "
", sep = "")

  environment()
})

A.4 実験3:本文の図7・図8・図9

# 本文コード
study3_env <- local({
required_packages <- c(
    "dplyr",
    "tidyr",
    "stringr",
    "purrr",
    "readr",
    "fixest",
    "tibble",
    "forcats",
    "ggplot2",
    "scales",
    "survival",
    "patchwork"
  )

  missing_packages <- required_packages[
    !vapply(required_packages, requireNamespace, logical(1), quietly = TRUE)
  ]

  if (length(missing_packages) > 0) {
    stop("No packages")
  }

  library(dplyr)
  library(tidyr)
  library(stringr)
  library(purrr)
  library(readr)
  library(fixest)
  library(tibble)
  library(forcats)
  library(ggplot2)
  library(scales)
  library(survival)
  library(patchwork)

  data_file <- unified_config$study3$data_file
  output_dir <- unified_config$study3$output_dir

  dir.create(output_dir, showWarnings = FALSE, recursive = TRUE)

  require_initial_consent <- TRUE
  require_final_consent <- TRUE
  final_consent_var <- "Q8.1"

  require_attention_check <- TRUE
  require_manipulation_check <- TRUE

  require_all_five_tasks <- TRUE

  attention_check_var <- "Q25.1_11"
  attention_check_correct <- "3"

  relative_cue_bootstrap_B <- unified_config$relative_cue_bootstrap_B
  relative_cue_bootstrap_seed <- unified_config$relative_cue_bootstrap_seed + 3L
  relative_cue_bootstrap_progress_every <- unified_config$relative_cue_bootstrap_progress_every

  rerun_relative_cue_bootstrap <- unified_config$rerun_relative_cue_bootstrap

  figure_font_family <- if (.Platform$OS.type == "windows") {
    "Yu Gothic"
  } else {
    ""
  }


  norm_text <- function(x) {
    x %>%
      as.character() %>%
      str_replace_all("\u3000", " ") %>%
      str_squish() %>%
      str_replace_all("~", "~") %>%
      str_replace_all("〜", "~")
  }

  as_num <- function(x) {
    suppressWarnings(readr::parse_number(norm_text(x)))
  }

  first_existing <- function(dat, candidates) {
    out <- candidates[candidates %in% names(dat)]
    if (length(out) == 0) {
      NA_character_
    } else {
      out[1]
    }
  }

  get_var <- function(dat, candidates) {
    v <- first_existing(dat, candidates)

    if (is.na(v)) {
      rep(NA_character_, nrow(dat))
    } else {
      dat[[v]]
    }
  }

  is_response_code <- function(x, code) {
    x_norm <- norm_text(x)
    code_chr <- as.character(code)

    x_norm == code_chr |
      str_detect(x_norm, paste0("\\(", code_chr, "\\)$"))
  }

  relevel_if_present <- function(x, ref) {
    x <- factor(x)

    if (ref %in% levels(x)) {
      relevel(x, ref = ref)
    } else {
      x
    }
  }

  factor_miss <- function(x, miss = "欠損・無回答") {
    x <- norm_text(x)
    x[is.na(x) | x == "" | x == "NA"] <- miss
    factor(x)
  }

  mean_impute <- function(x) {
    x <- as.numeric(x)
    miss <- as.integer(is.na(x))

    if (all(is.na(x))) {
      value <- x
    } else {
      value <- ifelse(
        is.na(x),
        mean(x, na.rm = TRUE),
        x
      )
    }

    list(
      value = value,
      miss = miss
    )
  }

  write_csv_safely <- function(x, filename) {
    readr::write_csv(
      x,
      file.path(output_dir, filename),
      na = ""
    )
  }

  save_plot <- function(
    filename,
    plot,
    width,
    height,
    dpi = 300
  ) {
    ggplot2::ggsave(
      filename = file.path(output_dir, filename),
      plot = plot,
      width = width,
      height = height,
      dpi = dpi
    )
  }

  canonicalize_party_name <- function(x) {
    x_norm <- norm_text(x)
    x_compact <- str_replace_all(x_norm, "\\s+", "")

    case_when(
      is.na(x_compact) | x_compact == "" ~ NA_character_,

      x_compact %in% c(
        "自由民主党",
        "自民党",
        "自民"
      ) ~ "自由民主党",

      x_compact %in% c(
        "立憲民主党",
        "立民"
      ) ~ "立憲民主党",

      x_compact %in% c(
        "日本維新の会",
        "維新"
      ) ~ "日本維新の会",

      x_compact == "公明党" ~ "公明党",

      x_compact %in% c(
        "国民民主党",
        "国民"
      ) ~ "国民民主党",

      x_compact %in% c(
        "れいわ新選組",
        "れいわ"
      ) ~ "れいわ新選組",

      x_compact == "参政党" ~ "参政党",

      x_compact %in% c(
        "日本共産党",
        "共産党"
      ) ~ "日本共産党",

      x_compact == "中道改革連合" ~ "中道改革連合",

      x_compact == "日本保守党" ~ "日本保守党",

      x_compact %in% c(
        "社会民主党",
        "社民党"
      ) ~ "社会民主党",

      x_compact == "チームみらい" ~ "チームみらい",

      TRUE ~ x_norm
    )
  }

  canonicalize_economic_level <- function(x) {
    x_norm <- norm_text(x) %>%
      str_replace_all("+", "+") %>%
      str_replace_all("−|-|―", "-") %>%
      str_replace_all("%", "%")

    case_when(
      is.na(x_norm) | x_norm == "" ~ NA_character_,

      str_detect(x_norm, "GDP") &
        str_detect(x_norm, "プラス|\\+\\s*1") ~
        "GDP成長率プラス1%",

      str_detect(x_norm, "GDP") &
        str_detect(x_norm, "マイナス|-\\s*1") ~
        "GDP成長率マイナス1%",

      str_detect(x_norm, "GDP") &
        str_detect(x_norm, \\s*0|0\\s*%|変わらず|変化なし") ~
        "GDP成長率±0%",

      str_detect(x_norm, "日経平均") &
        str_detect(x_norm, "プラス|\\+\\s*1000") ~
        "日経平均前月同期比プラス1000円",

      str_detect(x_norm, "日経平均") &
        str_detect(x_norm, "マイナス|-\\s*1000") ~
        "日経平均前月同期比マイナス1000円",

      str_detect(x_norm, "日経平均") &
        str_detect(x_norm, "変わらず|変化なし|±\\s*0|0\\s*円") ~
        "日経平均前月同期比変わらず",

      str_detect(x_norm, "CPI|物価") &
        str_detect(x_norm, "プラス|\\+\\s*1") ~
        "CPI前期比プラス1ポイント",

      str_detect(x_norm, "CPI|物価") &
        str_detect(x_norm, "マイナス|-\\s*1") ~
        "CPI前期比マイナス1ポイント",

      str_detect(x_norm, "CPI|物価") &
        str_detect(x_norm, \\s*0|0\\s*ポイント|変わらず|変化なし") ~
        "CPI前期比±0ポイント",

      str_detect(x_norm, "失業率|雇用") &
        str_detect(x_norm, "プラス|\\+\\s*1") ~
        "失業率前期比プラス1%",

      str_detect(x_norm, "失業率|雇用") &
        str_detect(x_norm, "マイナス|-\\s*1") ~
        "失業率前期比マイナス1%",

      str_detect(x_norm, "失業率|雇用") &
        str_detect(x_norm, \\s*0|0\\s*%|変わらず|変化なし") ~
        "失業率前期比±0%",

      TRUE ~ x_norm
    )
  }

  level_to_attr_var <- function(x) {
    x_norm <- canonicalize_economic_level(x)

    case_when(
      str_detect(x_norm, "^GDP成長率") ~ "gdp_growth",
      str_detect(x_norm, "^日経平均") ~ "nikkei",
      str_detect(x_norm, "^CPI") ~ "cpi",
      str_detect(x_norm, "^失業率") ~ "unemployment",
      TRUE ~ NA_character_
    )
  }

  tidy_fixest <- function(model) {
    ct <- as.data.frame(fixest::coeftable(model))
    ct$term <- rownames(ct)

    estimate_col <- intersect(
      c("Estimate", "estimate"),
      names(ct)
    )[1]

    se_col <- intersect(
      c("Std. Error", "Std. error", "std.error"),
      names(ct)
    )[1]

    statistic_col <- intersect(
      c("t value", "z value", "statistic"),
      names(ct)
    )[1]

    p_col <- intersect(
      c("Pr(>|t|)", "Pr(>|z|)", "p.value"),
      names(ct)
    )[1]

    if (
      is.na(estimate_col) |
        is.na(se_col) |
        is.na(statistic_col) |
        is.na(p_col)
    ) {
      stop("Check data")
    }

    ct %>%
      as_tibble() %>%
      transmute(
        term = term,
        estimate = .data[[estimate_col]],
        std.error = .data[[se_col]],
        statistic = .data[[statistic_col]],
        p.value = .data[[p_col]],
        conf.low = estimate - 1.96 * std.error,
        conf.high = estimate + 1.96 * std.error
      )
  }


  if (!file.exists(data_file)) {
    stop("Check data")
  }

  raw <- readr::read_csv(
    data_file,
    col_types = cols(.default = col_character()),
    show_col_types = FALSE,
    name_repair = "minimal"
  )


  if (require_final_consent) {
    final_consent_var <- detect_final_consent_column(
      raw = raw,
      preferred_candidates = c("Q8.1", "Q9.1", "Q10.1"),
      study_label = "Study 3"
    )
  }

  if (require_attention_check) {
    attention_check_var <- detect_attention_check_column(
      raw = raw,
      preferred_candidates = c("Q25.1_11", "Q25.1_10"),
      study_label = "Study 3"
    )
  }

  if (!"ResponseId" %in% names(raw)) {
    stop("Check data")
  }

  df_header_removed <- raw %>%
    filter(
      !is.na(ResponseId),
      ResponseId != "",
      !str_detect(
        norm_text(ResponseId),
        "^(Response ID|回答ID)$|ImportId"
      )
    ) %>%
    mutate(ID = as.character(ResponseId))

  duplicate_ids <- df_header_removed %>%
    count(ID) %>%
    filter(n > 1)

  if (nrow(duplicate_ids) > 0) {
    print(duplicate_ids)
    stop("Check")
  }

  sample_flow <- tibble(
    stage = "Qualtrics質問文行・ImportId行を除外後",
    n = nrow(df_header_removed)
  )

  df <- df_header_removed

  if (require_initial_consent) {
    if (!"Q1.1" %in% names(df)) {
      stop("Check initial consent")
    }

    df <- df %>%
      filter(
        is_response_code(Q1.1, 1) |
          str_detect(
            norm_text(Q1.1),
            "趣旨に同意して.*協力する"
          )
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(
        stage = "初回同意 Q1.1 = 1",
        n = nrow(df)
      )
    )
  }

  if (require_final_consent) {
    if (is.na(final_consent_var) || !final_consent_var %in% names(df)) {
      stop("Check final consent")
    }

    df <- df %>%
      filter(
        is_response_code(.data[[final_consent_var]], 1) |
          str_detect(
            norm_text(.data[[final_consent_var]]),
            "同意し.*回答結果を送信する"
          )
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(
        stage = paste0("最終同意 ", final_consent_var, " = 1"),
        n = nrow(df)
      )
    )
  }

  if (require_attention_check) {
    if (!attention_check_var %in% names(df)) {
      stop("Check attention item")
    }

    attention_check_correct <- detect_attention_correct_code(
      df[[attention_check_var]],
      displayed_answer = 3L,
      recoded_answer = 6L,
      study_label = "Study 3"
    )

    df <- df %>%
      filter(
        is_response_code(
          .data[[attention_check_var]],
          attention_check_correct
        )
      )

    sample_flow <- bind_rows(
      sample_flow,
      tibble(
        stage = paste0(
          "指示項目正答(",
          attention_check_var,
          "、保存コード=",
          attention_check_correct,
          ")"
        ),
        n = nrow(df)
      )
    )
  }

  print(sample_flow)
  write_csv_safely(
    sample_flow,
    "sample_flow_before_conjoint.csv"
  )


  choice_map <- detect_conjoint_choice_map(
    raw = raw,
    party_numbers = 2:5,
    study_label = "Study 3"
  )

  manipulation_map <- detect_manipulation_map(
    raw = raw,
    choice_map = choice_map,
    study_label = "Study 3"
  )

  write_csv_safely(choice_map, "detected_choice_question_map.csv")
  write_csv_safely(manipulation_map, "detected_manipulation_question_map.csv")


  required_attr_vars <- c(
    "party_name",
    "gdp_growth",
    "nikkei",
    "cpi",
    "unemployment"
  )

  expected_party_levels <- c(
    "自由民主党",
    "立憲民主党",
    "日本維新の会",
    "公明党",
    "国民民主党",
    "れいわ新選組",
    "参政党",
    "日本共産党",
    "中道改革連合"
  )

  allowed_economic_levels <- list(
    gdp_growth = c(
      "GDP成長率±0%",
      "GDP成長率プラス1%",
      "GDP成長率マイナス1%"
    ),

    nikkei = c(
      "日経平均前月同期比変わらず",
      "日経平均前月同期比プラス1000円",
      "日経平均前月同期比マイナス1000円"
    ),

    cpi = c(
      "CPI前期比±0ポイント",
      "CPI前期比プラス1ポイント",
      "CPI前期比マイナス1ポイント"
    ),

    unemployment = c(
      "失業率前期比±0%",
      "失業率前期比プラス1%",
      "失業率前期比マイナス1%"
    )
  )


  make_profile_long <- function(dat, n_party) {

    map_n <- choice_map %>%
      filter(party_n == n_party)

    qvars <- map_n$choice_var

    missing_q <- setdiff(qvars, names(dat))

    if (length(missing_q) > 0) {
      stop("Check choice columns")
    }

    dat_n <- dat %>%
      filter(
        if_any(
          all_of(qvars),
          ~ !is.na(.x) & norm_text(.x) != ""
        )
      )

    if (require_manipulation_check) {
      manipulation_row <- manipulation_map %>%
        filter(party_n == n_party)

      manipulation_var <- manipulation_row$manipulation_var
      correct_answer <- manipulation_row$correct_answer

      if (!manipulation_var %in% names(dat_n)) {
        stop("Check manipulation item")
      }

      dat_n <- dat_n %>%
        filter(
          is_response_code(
            .data[[manipulation_var]],
            correct_answer
          )
        )
    }

    choice_long <- dat_n %>%
      select(
        ID,
        all_of(qvars)
      ) %>%
      pivot_longer(
        cols = all_of(qvars),
        names_to = "choice_var",
        values_to = "choice_raw"
      ) %>%
      left_join(
        map_n,
        by = "choice_var"
      ) %>%
      mutate(
        choice = parse_choice_position(choice_raw)
      ) %>%
      filter(!is.na(choice)) %>%
      select(
        ID,
        party_n,
        task,
        choice
      )

    invalid_choice <- choice_long %>%
      filter(
        choice < 1 |
          choice > n_party
      )

    if (nrow(invalid_choice) > 0) {
      print(invalid_choice)
      stop("Check choice values")
    }

    duplicate_choice <- choice_long %>%
      count(
        ID,
        task
      ) %>%
      filter(n != 1)

    if (nrow(duplicate_choice) > 0) {
      print(duplicate_choice)
      stop("Check duplicate choices")
    }

    party_regex <- paste0(
      "^S3_P",
      n_party,
      "_PARTY_([1-5])_([1-",
      n_party,
      "])$"
    )

    party_cols <- names(dat_n)[
      str_detect(
        names(dat_n),
        party_regex
      )
    ]

    expected_party_cols_n <- 5 * n_party

    if (length(party_cols) != expected_party_cols_n) {
      stop("Check")
    }

    party_long <- dat_n %>%
      select(
        ID,
        all_of(party_cols)
      ) %>%
      pivot_longer(
        cols = all_of(party_cols),
        names_to = "party_var",
        values_to = "party_name_raw"
      ) %>%
      extract(
        party_var,
        into = c(
          "task",
          "profile"
        ),
        regex = party_regex,
        convert = TRUE
      ) %>%
      mutate(
        party_name = canonicalize_party_name(
          party_name_raw
        )
      ) %>%
      filter(
        task %in% 1:5,
        profile %in% 1:n_party,
        !is.na(party_name),
        party_name != ""
      ) %>%
      select(
        ID,
        task,
        profile,
        party_name
      )

    duplicate_party_name <- party_long %>%
      count(
        ID,
        task,
        profile
      ) %>%
      filter(n != 1)

    if (nrow(duplicate_party_name) > 0) {
      print(
        head(
          duplicate_party_name,
          50
        )
      )
      stop("Check")
    }

    level_regex <- paste0(
      "^S3_P",
      n_party,
      "_F_([1-5])_([1-",
      n_party,
      "])_([1-4])$"
    )

    level_cols <- names(dat_n)[
      str_detect(
        names(dat_n),
        level_regex
      )
    ]

    expected_level_cols_n <- 5 * n_party * 4

    if (length(level_cols) != expected_level_cols_n) {
      stop("Check attributes")
    }

    level_long <- dat_n %>%
      select(
        ID,
        all_of(level_cols)
      ) %>%
      pivot_longer(
        cols = all_of(level_cols),
        names_to = "fvar",
        values_to = "level_raw"
      ) %>%
      extract(
        fvar,
        into = c(
          "task",
          "profile",
          "attr_order"
        ),
        regex = level_regex,
        convert = TRUE
      ) %>%
      mutate(
        level = canonicalize_economic_level(
          level_raw
        ),
        attr_var = level_to_attr_var(
          level
        )
      ) %>%
      filter(
        task %in% 1:5,
        profile %in% 1:n_party,
        attr_order %in% 1:4,
        !is.na(level),
        level != ""
      )

    unknown_levels <- level_long %>%
      filter(
        is.na(attr_var)
      ) %>%
      distinct(
        level_raw,
        level
      )

    if (nrow(unknown_levels) > 0) {
      print(unknown_levels)
      stop("Check attributes")
    }

    profile_attribute_count <- level_long %>%
      count(
        ID,
        task,
        profile,
        name = "n_attribute_rows"
      ) %>%
      filter(
        n_attribute_rows != 4
      )

    if (nrow(profile_attribute_count) > 0) {
      print(
        head(
          profile_attribute_count,
          50
        )
      )
      stop("Check attributes")
    }

    duplicate_attribute <- level_long %>%
      count(
        ID,
        task,
        profile,
        attr_var
      ) %>%
      filter(n != 1)

    if (nrow(duplicate_attribute) > 0) {
      print(
        head(
          duplicate_attribute,
          50
        )
      )
      stop("Check attributes")
    }

    economic_wide <- level_long %>%
      select(
        ID,
        task,
        profile,
        attr_var,
        level
      ) %>%
      pivot_wider(
        names_from = attr_var,
        values_from = level,
        values_fn = list(
          level = ~ first(.x)
        )
      )

    profile_wide <- party_long %>%
      inner_join(
        economic_wide,
        by = c(
          "ID",
          "task",
          "profile"
        )
      ) %>%
      inner_join(
        choice_long,
        by = c(
          "ID",
          "task"
        )
      ) %>%
      mutate(
        party_n = n_party,
        selected = as.integer(
          profile == choice
        ),
        task_id = paste(
          ID,
          party_n,
          task,
          sep = "_"
        ),
        profile_id = paste(
          ID,
          party_n,
          task,
          profile,
          sep = "_"
        )
      )

    missing_attr <- setdiff(
      required_attr_vars,
      names(profile_wide)
    )

    if (length(missing_attr) > 0) {
      stop("Check attributes")
    }

    profile_wide <- profile_wide %>%
      select(
        ID,
        party_n,
        task,
        profile,
        choice,
        selected,
        task_id,
        profile_id,
        all_of(required_attr_vars)
      ) %>%
      arrange(
        ID,
        task,
        profile
      )

    return(profile_wide)
  }


  conjoint_2 <- make_profile_long(
    df,
    2
  )

  conjoint_3 <- make_profile_long(
    df,
    3
  )

  conjoint_4 <- make_profile_long(
    df,
    4
  )

  conjoint_5 <- make_profile_long(
    df,
    5
  )

  conjoint_all_unfiltered <- bind_rows(
    conjoint_2,
    conjoint_3,
    conjoint_4,
    conjoint_5
  )


  id_task_check <- conjoint_all_unfiltered %>%
    group_by(
      ID,
      party_n,
      task
    ) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    group_by(
      ID,
      party_n
    ) %>%
    summarise(
      n_tasks = n_distinct(task),
      all_tasks_ok = all(
        n_profiles == party_n &
          selected_sum == 1
      ),
      .groups = "drop"
    )

  if (require_all_five_tasks) {
    valid_ids <- id_task_check %>%
      filter(
        n_tasks == 5,
        all_tasks_ok
      )
  } else {
    valid_ids <- id_task_check %>%
      filter(all_tasks_ok)
  }

  conjoint_all <- conjoint_all_unfiltered %>%
    semi_join(
      valid_ids,
      by = c(
        "ID",
        "party_n"
      )
    )

  sample_flow <- bind_rows(
    sample_flow,
    tibble(
      stage = if (require_all_five_tasks) {
        "5課題すべてが完全な回答者"
      } else {
        "回答済み課題がすべて完全な回答者"
      },
      n = n_distinct(conjoint_all$ID)
    )
  )

  n_by_party <- valid_ids %>%
    count(
      party_n,
      name = "n"
    ) %>%
    complete(
      party_n = 2:5,
      fill = list(n = 0)
    ) %>%
    arrange(party_n)

  n_total <- valid_ids %>%
    summarise(
      n = n_distinct(ID)
    ) %>%
    pull(n)

  figure_n_labels <- bind_rows(
    tibble(
      position = "全サンプル",
      label = paste0(
        "全サンプル, n=",
        scales::comma(n_total)
      )
    ),

    n_by_party %>%
      mutate(
        position = paste0(
          party_n,
          "選択肢"
        ),
        label = paste0(
          "n=",
          scales::comma(n)
        )
      ) %>%
      select(
        position,
        label
      )
  )

  cat("\n分析対象者数\n")
  print(n_by_party)
  cat(
    "全サンプル n=",
    n_total,
    "\n",
    sep = ""
  )

  write_csv_safely(
    sample_flow,
    "sample_flow.csv"
  )

  write_csv_safely(
    id_task_check,
    "id_task_check.csv"
  )

  write_csv_safely(
    valid_ids,
    "valid_ids.csv"
  )

  write_csv_safely(
    n_by_party,
    "n_by_party.csv"
  )

  write_csv_safely(
    figure_n_labels,
    "figure_n_labels.csv"
  )


  check_profile <- conjoint_all %>%
    group_by(
      party_n,
      ID,
      task,
      task_id
    ) %>%
    summarise(
      n_profiles = n(),
      selected_sum = sum(selected),
      .groups = "drop"
    ) %>%
    count(
      party_n,
      n_profiles,
      selected_sum
    )

  print(check_profile)

  stopifnot(
    all(
      check_profile$n_profiles ==
        check_profile$party_n
    )
  )

  stopifnot(
    all(
      check_profile$selected_sum == 1
    )
  )

  allowed_economic_df <- enframe(
    allowed_economic_levels,
    name = "name",
    value = "value"
  ) %>%
    unnest(value)

  unexpected_economic_values <- conjoint_all %>%
    select(
      all_of(
        names(allowed_economic_levels)
      )
    ) %>%
    pivot_longer(
      cols = everything(),
      names_to = "name",
      values_to = "value"
    ) %>%
    filter(
      !is.na(value),
      value != ""
    ) %>%
    distinct(
      name,
      value
    ) %>%
    anti_join(
      allowed_economic_df,
      by = c(
        "name",
        "value"
      )
    )

  print(unexpected_economic_values)

  stopifnot(
    nrow(unexpected_economic_values) == 0
  )

  observed_party_levels <- conjoint_all %>%
    distinct(party_name) %>%
    arrange(party_name)

  observed_economic_levels <- conjoint_all %>%
    select(
      all_of(
        names(allowed_economic_levels)
      )
    ) %>%
    pivot_longer(
      cols = everything(),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    distinct(
      attribute,
      level
    ) %>%
    arrange(
      attribute,
      level
    )

  party_level_frequency <- conjoint_all %>%
    count(
      party_n,
      party_name,
      name = "n_profiles"
    ) %>%
    group_by(party_n) %>%
    mutate(
      proportion = n_profiles /
        sum(n_profiles)
    ) %>%
    ungroup()

  economic_level_frequency <- conjoint_all %>%
    select(
      party_n,
      all_of(
        names(allowed_economic_levels)
      )
    ) %>%
    pivot_longer(
      cols = all_of(
        names(allowed_economic_levels)
      ),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    count(
      party_n,
      attribute,
      level,
      name = "n_profiles"
    ) %>%
    group_by(
      party_n,
      attribute
    ) %>%
    mutate(
      proportion = n_profiles /
        sum(n_profiles)
    ) %>%
    ungroup()

  write_csv_safely(
    check_profile,
    "profile_expansion_check.csv"
  )

  write_csv_safely(
    observed_party_levels,
    "observed_party_levels.csv"
  )

  write_csv_safely(
    observed_economic_levels,
    "observed_economic_levels.csv"
  )

  write_csv_safely(
    party_level_frequency,
    "party_level_frequency.csv"
  )

  write_csv_safely(
    economic_level_frequency,
    "economic_level_frequency.csv"
  )

  write_csv_safely(
    conjoint_all,
    "study3_profile_level_data.csv"
  )


  analysis_ids <- valid_ids %>%
    select(
      ID,
      party_n
    )

  if (attention_check_var %in% names(df)) {
    attention_summary <- df %>%
      semi_join(
        analysis_ids,
        by = "ID"
      ) %>%
      transmute(
        ID,
        attention_response = norm_text(
          .data[[attention_check_var]]
        ),
        attention_pass = is_response_code(
          .data[[attention_check_var]],
          attention_check_correct
        )
      ) %>%
      count(
        attention_response,
        attention_pass,
        name = "n"
      ) %>%
      arrange(
        desc(attention_pass),
        attention_response
      )
  } else {
    attention_summary <- tibble(
      attention_response = character(),
      attention_pass = logical(),
      n = integer()
    )
  }

  manipulation_summary <- map_dfr(
    2:5,
    function(n_party) {
      manipulation_row <- manipulation_map %>%
        filter(
          party_n == n_party
        )

      v <- manipulation_row$manipulation_var
      correct <- manipulation_row$correct_answer

      if (!v %in% names(df)) {
        return(
          tibble(
            party_n = n_party,
            response = NA_character_,
            correct = NA,
            n = 0L
          )
        )
      }

      df %>%
        semi_join(
          analysis_ids %>%
            filter(
              party_n == n_party
            ),
          by = "ID"
        ) %>%
        transmute(
          party_n = n_party,
          response = norm_text(
            .data[[v]]
          ),
          correct = is_response_code(
            .data[[v]],
            correct
          )
        ) %>%
        count(
          party_n,
          response,
          correct,
          name = "n"
        )
    }
  )

  write_csv_safely(
    attention_summary,
    "attention_check_summary.csv"
  )

  write_csv_safely(
    manipulation_summary,
    "party_number_check_summary.csv"
  )


  observed_party_vector <- conjoint_all %>%
    distinct(party_name) %>%
    pull(party_name)

  party_reference <- if (
    "自由民主党" %in% observed_party_vector
  ) {
    "自由民主党"
  } else {
    sort(observed_party_vector)[1]
  }

  if (party_reference != "自由民主党") {
    warning("Check")
  }

  party_levels_use <- c(
    party_reference,

    expected_party_levels[
      expected_party_levels %in%
        observed_party_vector &
        expected_party_levels !=
        party_reference
    ],

    sort(
      setdiff(
        observed_party_vector,
        expected_party_levels
      )
    )
  ) %>%
    unique()

  conjoint_all_m <- conjoint_all %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),

      party_name = factor(
        party_name,
        levels = party_levels_use
      ),

      gdp_growth = factor(
        gdp_growth,
        levels = allowed_economic_levels$gdp_growth
      ),

      nikkei = factor(
        nikkei,
        levels = allowed_economic_levels$nikkei
      ),

      cpi = factor(
        cpi,
        levels = allowed_economic_levels$cpi
      ),

      unemployment = factor(
        unemployment,
        levels = allowed_economic_levels$unemployment
      ),

      party_n_f = factor(
        as.character(party_n),
        levels = c(
          "2",
          "3",
          "4",
          "5"
        )
      ),

      party_n_c = party_n - 2
    )

  attr_terms <- c(
    "party_name",
    "gdp_growth",
    "nikkei",
    "cpi",
    "unemployment"
  )

  economic_attr_terms <- c(
    "gdp_growth",
    "nikkei",
    "cpi",
    "unemployment"
  )


  formula_nocov <- as.formula(
    paste(
      "selected ~",
      paste(
        attr_terms,
        collapse = " + "
      )
    )
  )

  run_amce_nocov <- function(dat) {
    feols(
      formula_nocov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_nocov <- conjoint_all_m %>%
    split(.$party_n) %>%
    map(run_amce_nocov)

  capture.output(
    etable(
      models_by_party_n_nocov
    ),
    file = file.path(
      output_dir,
      "amce_nocov_models.txt"
    )
  )


  m_interaction <- feols(
    selected ~
      party_n_f *
      (
        party_name +
          gdp_growth +
          nikkei +
          cpi +
          unemployment
      ),
    data = conjoint_all_m,
    vcov = ~ ID
  )

  capture.output(
    summary(m_interaction),
    file = file.path(
      output_dir,
      "amce_interaction_model.txt"
    )
  )


  m_linear_trend <- feols(
    selected ~
      party_n_c *
      (
        party_name +
          gdp_growth +
          nikkei +
          cpi +
          unemployment
      ),
    data = conjoint_all_m,
    vcov = ~ ID
  )

  capture.output(
    summary(m_linear_trend),
    file = file.path(
      output_dir,
      "amce_linear_trend_model.txt"
    )
  )


  party_term_labels <- tibble(
    term = paste0(
      "party_name",
      party_levels_use[-1]
    ),
    attribute = "政権与党の政党名",
    cue_type = "政党名の手がかり",
    label = party_levels_use[-1],
    order = seq_along(
      party_levels_use[-1]
    )
  )

  economic_term_labels <- tribble(
    ~term, ~attribute, ~cue_type, ~label, ~order,

    "gdp_growthGDP成長率プラス1%",
    "GDP成長率",
    "経済の手がかり",
    "GDP:プラス1%",
    1,

    "gdp_growthGDP成長率マイナス1%",
    "GDP成長率",
    "経済の手がかり",
    "GDP:マイナス1%",
    2,

    "nikkei日経平均前月同期比プラス1000円",
    "日経平均",
    "経済の手がかり",
    "日経平均:プラス1000円",
    3,

    "nikkei日経平均前月同期比マイナス1000円",
    "日経平均",
    "経済の手がかり",
    "日経平均:マイナス1000円",
    4,

    "cpiCPI前期比プラス1ポイント",
    "CPI",
    "経済の手がかり",
    "CPI:プラス1ポイント",
    5,

    "cpiCPI前期比マイナス1ポイント",
    "CPI",
    "経済の手がかり",
    "CPI:マイナス1ポイント",
    6,

    "unemployment失業率前期比プラス1%",
    "失業率",
    "経済の手がかり",
    "失業率:プラス1%",
    7,

    "unemployment失業率前期比マイナス1%",
    "失業率",
    "経済の手がかり",
    "失業率:マイナス1%",
    8
  )

  term_labels <- bind_rows(
    party_term_labels %>%
      mutate(
        order_global = order
      ),

    economic_term_labels %>%
      mutate(
        order_global =
          max(
            c(
              party_term_labels$order,
              0
            )
          ) +
          order
      )
  ) %>%
    select(
      term,
      attribute,
      cue_type,
      label,
      order = order_global
    )

  attribute_order <- c(
    "政権与党の政党名",
    "GDP成長率",
    "日経平均",
    "CPI",
    "失業率"
  )

  label_order <- term_labels %>%
    arrange(order) %>%
    pull(label)

  make_amce_plot_df <- function(models) {
    imap_dfr(
      models,
      ~ tidy_fixest(.x) %>%
        mutate(
          party_n = as.character(.y)
        )
    ) %>%
      left_join(
        term_labels,
        by = "term"
      ) %>%
      filter(
        !is.na(attribute)
      ) %>%
      mutate(
        estimate_pp = estimate * 100,
        conf.low_pp = conf.low * 100,
        conf.high_pp = conf.high * 100,

        party_n = factor(
          party_n,
          levels = c(
            "2",
            "3",
            "4",
            "5"
          ),
          labels = c(
            "2選択肢",
            "3選択肢",
            "4選択肢",
            "5選択肢"
          )
        ),

        attribute = factor(
          attribute,
          levels = attribute_order
        ),

        label = factor(
          label,
          levels = rev(
            label_order
          )
        )
      )
  }

  amce_plot_nocov <- make_amce_plot_df(
    models_by_party_n_nocov
  )

  write_csv_safely(
    amce_plot_nocov,
    "amce_nocov_coefficients.csv"
  )

  interaction_plot_df <- tidy_fixest(
    m_interaction
  ) %>%
    filter(
      str_detect(
        term,
        "party_n_f[345]"
      )
    ) %>%
    mutate(
      party_n_code = str_extract(
        term,
        "party_n_f[345]"
      ),

      party_n = str_remove(
        party_n_code,
        "party_n_f"
      ),

      base_term = term %>%
        str_remove(
          "party_n_f[345]:"
        ) %>%
        str_remove(
          ":party_n_f[345]"
        )
    ) %>%
    left_join(
      term_labels,
      by = c(
        "base_term" = "term"
      )
    ) %>%
    filter(
      !is.na(attribute)
    ) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,

      party_n_label = factor(
        party_n,
        levels = c(
          "3",
          "4",
          "5"
        ),
        labels = c(
          "3選択肢",
          "4選択肢",
          "5選択肢"
        )
      ),

      attribute = factor(
        attribute,
        levels = attribute_order
      ),

      label = factor(
        label,
        levels = rev(
          label_order
        )
      )
    )

  write_csv_safely(
    interaction_plot_df,
    "amce_interaction_coefficients.csv"
  )

  linear_trend_plot_df <- tidy_fixest(
    m_linear_trend
  ) %>%
    filter(
      str_detect(
        term,
        "party_n_c:"
      ) |
        str_detect(
          term,
          ":party_n_c"
        )
    ) %>%
    mutate(
      base_term = term %>%
        str_remove(
          "party_n_c:"
        ) %>%
        str_remove(
          ":party_n_c"
        )
    ) %>%
    left_join(
      term_labels,
      by = c(
        "base_term" = "term"
      )
    ) %>%
    filter(
      !is.na(attribute)
    ) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,

      attribute = factor(
        attribute,
        levels = attribute_order
      ),

      label = factor(
        label,
        levels = rev(
          label_order
        )
      )
    )

  write_csv_safely(
    linear_trend_plot_df,
    "amce_linear_trend_coefficients.csv"
  )


  recode_female_study3 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num == 2 ~ 1L,
      x_num == 1 ~ 0L,
      TRUE ~ NA_integer_
    )
  }

  recode_college_grad_study3 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num %in% c(
        4,
        5
      ) ~ 1L,

      x_num %in% c(
        1,
        2,
        3
      ) ~ 0L,

      TRUE ~ NA_integer_
    )
  }

  recode_self_ideology_study3 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num %in% 1:8 ~ x_num,
      x_num == 12 ~ 9,
      x_num == 13 ~ 10,
      x_num == 14 ~ 11,
      TRUE ~ NA_real_
    )
  }

  recode_party_support_study3 <- function(x) {
    x_num <- as_num(x)

    case_when(
      x_num == 1 ~ "自由民主党",
      x_num == 2 ~ "中道改革連合",
      x_num == 3 ~ "立憲民主党",
      x_num == 4 ~ "公明党",
      x_num == 5 ~ "日本維新の会",
      x_num == 6 ~ "国民民主党",
      x_num == 7 ~ "れいわ新選組",
      x_num == 8 ~ "日本共産党",
      x_num == 9 ~ "参政党",
      x_num == 10 ~ "日本保守党",
      x_num == 11 ~ "社会民主党",
      x_num == 12 ~ "チームみらい",
      x_num == 13 ~ "その他",
      x_num == 14 ~ "支持政党なし",
      x_num == 15 ~ "わからない",
      x_num == 16 ~ "答えたくない",
      TRUE ~ NA_character_
    )
  }

  gender_raw <- get_var(
    df,
    c(
      "Q2.1",
      "Q2_1"
    )
  )

  age_raw <- get_var(
    df,
    c(
      "Q2.2_13",
      "Q2.2.13",
      "Q2_2_13",
      "Q2.2_2",
      "Q2.2.2",
      "Q2_2_2"
    )
  )

  education_raw <- get_var(
    df,
    c(
      "Q2.3",
      "Q2_3"
    )
  )

  region_raw <- get_var(
    df,
    c(
      "Q2.4_1",
      "Q2.4.1",
      "Q2_4_1"
    )
  )

  prefecture_raw <- get_var(
    df,
    c(
      "Q2.4_2",
      "Q2.4.2",
      "Q2_4_2"
    )
  )

  income_gross_raw <- get_var(
    df,
    c(
      "Q2.5_1",
      "Q2.5.1",
      "Q2_5_1"
    )
  )

  income_net_raw <- get_var(
    df,
    c(
      "Q2.5_2",
      "Q2.5.2",
      "Q2_5_2"
    )
  )

  zero_income_reason_raw <- get_var(
    df,
    c(
      "Q2.6",
      "Q2_6"
    )
  )

  self_ideology_raw <- get_var(
    df,
    c(
      "Q25.1_1",
      "Q25.1.1",
      "Q25_1_1"
    )
  )

  party_support_raw <- get_var(
    df,
    c(
      "Q7.2",
      "Q7_2"
    )
  )

  covar_id <- df %>%
    transmute(
      ID = as.character(ResponseId),

      female = recode_female_study3(
        gender_raw
      ),

      age = as_num(
        age_raw
      ),

      college_grad = recode_college_grad_study3(
        education_raw
      ),

      region = factor_miss(
        region_raw
      ),

      prefecture = factor_miss(
        prefecture_raw
      ),

      income_gross = as_num(
        income_gross_raw
      ),

      income_net = as_num(
        income_net_raw
      ),

      income_gross_log = log1p(
        income_gross
      ),

      income_net_log = log1p(
        income_net
      ),

      zero_income_reason = factor_miss(
        zero_income_reason_raw
      ),

      self_ideology = recode_self_ideology_study3(
        self_ideology_raw
      ),

      party_support = recode_party_support_study3(
        party_support_raw
      ),

      party_support_f = factor_miss(
        party_support
      ),

      party_support_profile = canonicalize_party_name(
        party_support
      )
    ) %>%
    semi_join(
      valid_ids %>%
        select(ID),
      by = "ID"
    ) %>%
    distinct(
      ID,
      .keep_all = TRUE
    )

  covar_id <- covar_id %>%
    mutate(
      age = if_else(
        age >= 18 &
          age <= 79,
        age,
        NA_real_
      )
    )

  age_imp_obj <- mean_impute(
    covar_id$age
  )

  income_gross_imp_obj <- mean_impute(
    covar_id$income_gross_log
  )

  self_ideology_imp_obj <- mean_impute(
    covar_id$self_ideology
  )

  covar_id <- covar_id %>%
    mutate(
      female_imp = if_else(
        is.na(female),
        0L,
        female
      ),

      female_miss = as.integer(
        is.na(female)
      ),

      college_grad_imp = if_else(
        is.na(college_grad),
        0L,
        college_grad
      ),

      college_grad_miss = as.integer(
        is.na(college_grad)
      ),

      age_imp = age_imp_obj$value,

      age_miss = age_imp_obj$miss,

      income_gross_log_imp =
        income_gross_imp_obj$value,

      income_gross_log_miss =
        income_gross_imp_obj$miss,

      self_ideology_imp =
        self_ideology_imp_obj$value,

      self_ideology_miss =
        self_ideology_imp_obj$miss
    )

  covariate_missing_summary <- covar_id %>%
    summarise(
      n_ids = n_distinct(ID),
      female_missing = sum(
        is.na(female)
      ),
      age_missing = sum(
        is.na(age)
      ),
      college_grad_missing = sum(
        is.na(college_grad)
      ),
      income_gross_missing = sum(
        is.na(income_gross_log)
      ),
      self_ideology_missing = sum(
        is.na(self_ideology)
      ),
      party_support_missing = sum(
        is.na(party_support)
      )
    )

  zero_income_summary <- covar_id %>%
    count(
      zero_income_reason,
      name = "n"
    ) %>%
    arrange(
      desc(n)
    )

  print(covariate_missing_summary)

  write_csv_safely(
    covar_id,
    "respondent_covariates.csv"
  )

  write_csv_safely(
    covariate_missing_summary,
    "covariate_missing_summary.csv"
  )

  write_csv_safely(
    zero_income_summary,
    "zero_income_reason_summary.csv"
  )


  conjoint_all_cov <- conjoint_all_m %>%
    left_join(
      covar_id,
      by = "ID"
    )

  covariate_terms <- c(
    "female_imp",
    "female_miss",
    "age_imp",
    "age_miss",
    "college_grad_imp",
    "college_grad_miss",
    "income_gross_log_imp",
    "income_gross_log_miss",
    "self_ideology_imp",
    "self_ideology_miss",
    "party_support_f"
  )

  has_variation <- function(dat, v) {
    if (!v %in% names(dat)) {
      return(FALSE)
    }

    dplyr::n_distinct(
      dat[[v]],
      na.rm = TRUE
    ) > 1
  }

  covariate_terms_use <- covariate_terms[
    map_lgl(
      covariate_terms,
      ~ has_variation(
        conjoint_all_cov,
        .x
      )
    )
  ]

  formula_cov <- as.formula(
    paste(
      "selected ~",
      paste(
        c(
          attr_terms,
          covariate_terms_use
        ),
        collapse = " + "
      )
    )
  )

  run_amce_cov <- function(dat) {
    feols(
      formula_cov,
      data = dat,
      vcov = ~ ID
    )
  }

  models_by_party_n_cov <- conjoint_all_cov %>%
    split(.$party_n) %>%
    map(run_amce_cov)

  capture.output(
    etable(
      models_by_party_n_nocov,
      models_by_party_n_cov,
      headers = c(
        rep(
          "共変量なし",
          length(
            models_by_party_n_nocov
          )
        ),
        rep(
          "共変量あり",
          length(
            models_by_party_n_cov
          )
        )
      )
    ),
    file = file.path(
      output_dir,
      "amce_nocov_and_cov_models.txt"
    )
  )

  amce_plot_cov <- make_amce_plot_df(
    models_by_party_n_cov
  )

  write_csv_safely(
    amce_plot_cov,
    "amce_cov_coefficients.csv"
  )


  study_label <- "実験3(2026年)"

  p_amce_cov <- ggplot(
    amce_plot_cov,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(
        width = 0.65
      ),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(
        width = 0.65
      ),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) {
        paste0(x, " pp")
      },
      breaks = scales::pretty_breaks(
        n = 8
      )
    ) +
    scale_shape_manual(
      name = "選択肢数",
      values = c(
        "2選択肢" = 16,
        "3選択肢" = 17,
        "4選択肢" = 15,
        "5選択肢" = 1
      )
    ) +
    scale_linetype_manual(
      name = "選択肢数",
      values = c(
        "2選択肢" = "solid",
        "3選択肢" = "dashed",
        "4選択肢" = "dotted",
        "5選択肢" = "dotdash"
      )
    ) +
    labs(
      subtitle = paste0(
        "政党名の基準カテゴリ:",
        party_reference,
        "。経済属性は変化なしを基準とする。"
      ),
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(
        size = 10
      ),
      legend.position = "top",
      legend.title = element_text(
        face = "bold"
      ),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(
        size = 9
      ),
      axis.title.x = element_text(
        face = "bold"
      )
    )

  print(p_amce_cov)

  save_plot(
    "amce_cov_facet_model.png",
    p_amce_cov,
    width = 10.5,
    height = 11.5
  )


  p_amce_nocov <- ggplot(
    amce_plot_nocov,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(
        width = 0.65
      ),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(
        width = 0.65
      ),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) {
        paste0(x, " pp")
      },
      breaks = scales::pretty_breaks(
        n = 8
      )
    ) +
    scale_shape_manual(
      name = "選択肢数",
      values = c(
        "2選択肢" = 16,
        "3選択肢" = 17,
        "4選択肢" = 15,
        "5選択肢" = 1
      )
    ) +
    scale_linetype_manual(
      name = "選択肢数",
      values = c(
        "2選択肢" = "solid",
        "3選択肢" = "dashed",
        "4選択肢" = "dotted",
        "5選択肢" = "dotdash"
      )
    ) +
    labs(
      subtitle = paste0(
        "政党名の基準カテゴリ:",
        party_reference,
        "。経済属性は変化なしを基準とする。"
      ),
      x = "選択確率の変化",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 16
      ),
      plot.subtitle = element_text(
        size = 10
      ),
      legend.position = "top",
      legend.title = element_text(
        face = "bold"
      ),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(
        size = 9
      ),
      axis.title.x = element_text(
        face = "bold"
      )
    )

  print(p_amce_nocov)

  save_plot(
    "amce_nocov_facet_model.png",
    p_amce_nocov,
    width = 10.5,
    height = 11.5
  )


  p_interaction <- ggplot(
    interaction_plot_df,
    aes(
      x = estimate_pp,
      y = label,
      shape = party_n_label,
      linetype = party_n_label,
      group = party_n_label
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      position = position_dodge(
        width = 0.65
      ),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(
        width = 0.65
      ),
      size = 2.5,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) {
        paste0(x, " pp")
      },
      breaks = scales::pretty_breaks(
        n = 8
      )
    ) +
    scale_shape_manual(
      name = "2選択肢条件との比較",
      values = c(
        "3選択肢" = 17,
        "4選択肢" = 15,
        "5選択肢" = 1
      )
    ) +
    scale_linetype_manual(
      name = "2選択肢条件との比較",
      values = c(
        "3選択肢" = "dashed",
        "4選択肢" = "dotted",
        "5選択肢" = "dotdash"
      )
    ) +
    labs(
      x = "2選択肢条件との差",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 15
      ),
      legend.position = "top",
      legend.title = element_text(
        face = "bold"
      ),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(
        size = 9
      ),
      axis.title.x = element_text(
        face = "bold"
      )
    )

  print(p_interaction)

  save_plot(
    "amce_interaction_difference_from_2choice.png",
    p_interaction,
    width = 10.5,
    height = 11.5
  )


  p_linear_trend <- ggplot(
    linear_trend_plot_df,
    aes(
      x = estimate_pp,
      y = label
    )
  ) +
    geom_vline(
      xintercept = 0,
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      height = 0.16,
      linewidth = 0.55,
      color = "black"
    ) +
    geom_point(
      size = 2.5,
      shape = 21,
      color = "black",
      fill = "white",
      stroke = 0.8
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_x_continuous(
      labels = function(x) {
        paste0(x, " pp")
      },
      breaks = scales::pretty_breaks(
        n = 8
      )
    ) +
    labs(
      subtitle = "横軸は、選択肢数が1つ増えたときの属性効果の変化",
      x = "1選択肢増加当たりのAMCE変化",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      plot.title = element_text(
        face = "bold",
        size = 15
      ),
      plot.subtitle = element_text(
        size = 10
      ),
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold",
        size = 10
      ),
      axis.text.y = element_text(
        size = 9
      ),
      axis.title.x = element_text(
        face = "bold"
      )
    )

  print(p_linear_trend)

  save_plot(
    "amce_linear_trend.png",
    p_linear_trend,
    width = 10.5,
    height = 11.5
  )


  heatmap_df <- amce_plot_cov %>%
    mutate(
      abs_amce = abs(
        estimate_pp
      )
    ) %>%
    group_by(party_n) %>%
    mutate(
      rank_within_condition =
        min_rank(
          desc(abs_amce)
        ),

      n_in_condition = n(),

      rank_score = if_else(
        n_in_condition == 1,
        1,
        1 -
          (
            rank_within_condition - 1
          ) /
          (
            n_in_condition - 1
          )
      )
    ) %>%
    ungroup()

  heatmap_row_order <- heatmap_df %>%
    group_by(
      label,
      attribute
    ) %>%
    summarise(
      mean_abs_amce = mean(
        abs_amce,
        na.rm = TRUE
      ),
      .groups = "drop"
    ) %>%
    arrange(
      desc(mean_abs_amce)
    ) %>%
    pull(label) %>%
    as.character()

  heatmap_df <- heatmap_df %>%
    mutate(
      label_heat = factor(
        as.character(label),
        levels = rev(
          heatmap_row_order
        )
      )
    )

  p_heat_amce <- ggplot(
    heatmap_df,
    aes(
      x = party_n,
      y = label_heat,
      fill = abs_amce
    )
  ) +
    geom_tile(
      color = "grey45",
      linewidth = 0.3
    ) +
    geom_text(
      aes(
        label = sprintf(
          "%.1f",
          estimate_pp
        ),
        color = if_else(
          rank_score >= 0.55,
          "white",
          "black"
        )
      ),
      size = 3.1
    ) +
    scale_color_identity() +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    scale_fill_gradient(
      low = "white",
      high = "grey20",
      name = "|AMCE|\n(pp)"
    ) +
    labs(
      subtitle = "セル内の数値は符号付きAMCE(percentage points)",
      x = "選択肢数",
      y = NULL
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      plot.title = element_text(
        face = "bold"
      ),
      legend.position = "right",
      panel.grid = element_blank(),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold"
      ),
      axis.text.y = element_text(
        size = 8.5
      )
    )

  print(p_heat_amce)

  save_plot(
    "amce_cov_heatmap.png",
    p_heat_amce,
    width = 10.5,
    height = 11.5
  )


  conjoint_clogit <- conjoint_all_m %>%
    mutate(
      selected = as.integer(selected),
      ID = as.character(ID),
      task_id = factor(task_id),

      party_name = relevel_if_present(
        party_name,
        party_reference
      ),

      gdp_growth = relevel_if_present(
        gdp_growth,
        allowed_economic_levels$gdp_growth[1]
      ),

      nikkei = relevel_if_present(
        nikkei,
        allowed_economic_levels$nikkei[1]
      ),

      cpi = relevel_if_present(
        cpi,
        allowed_economic_levels$cpi[1]
      ),

      unemployment = relevel_if_present(
        unemployment,
        allowed_economic_levels$unemployment[1]
      )
    )

  formula_clogit_nocov <- as.formula(
    paste0(
      "selected ~ ",
      paste(
        attr_terms,
        collapse = " + "
      ),
      " + strata(task_id) + cluster(ID)"
    )
  )

  run_clogit_nocov <- function(dat) {
    survival::clogit(
      formula_clogit_nocov,
      data = dat,
      method = "efron"
    )
  }

  models_clogit_nocov <- conjoint_clogit %>%
    split(.$party_n) %>%
    map(run_clogit_nocov)

  capture.output(
    lapply(
      models_clogit_nocov,
      summary
    ),
    file = file.path(
      output_dir,
      "conditional_logit_models.txt"
    )
  )

  tidy_clogit <- function(model) {
    s <- summary(model)
    ct <- as.data.frame(
      s$coefficients
    )
    ct$term <- rownames(ct)

    se_col <- if (
      "robust se" %in% names(ct)
    ) {
      "robust se"
    } else if (
      "se(coef)" %in% names(ct)
    ) {
      "se(coef)"
    } else {
      stop("Check clogit")
    }

    p_col <- if (
      "Pr(>|z|)" %in% names(ct)
    ) {
      "Pr(>|z|)"
    } else if (
      "Pr(>|t|)" %in% names(ct)
    ) {
      "Pr(>|t|)"
    } else {
      NA_character_
    }

    ct %>%
      as_tibble() %>%
      transmute(
        term = term,
        estimate = coef,
        std.error = .data[[se_col]],

        p.value = if (
          !is.na(p_col)
        ) {
          .data[[p_col]]
        } else {
          NA_real_
        },

        conf.low =
          estimate -
          1.96 *
          std.error,

        conf.high =
          estimate +
          1.96 *
          std.error,

        odds_ratio = exp(
          estimate
        ),

        odds_ratio_low = exp(
          conf.low
        ),

        odds_ratio_high = exp(
          conf.high
        )
      )
  }

  clogit_plot_df <- imap_dfr(
    models_clogit_nocov,
    ~ tidy_clogit(.x) %>%
      mutate(
        party_n = as.character(.y)
      )
  ) %>%
    left_join(
      term_labels,
      by = "term"
    ) %>%
    filter(
      !is.na(attribute)
    ) %>%
    mutate(
      party_n = factor(
        party_n,
        levels = c(
          "2",
          "3",
          "4",
          "5"
        ),
        labels = c(
          "2選択肢",
          "3選択肢",
          "4選択肢",
          "5選択肢"
        )
      ),

      attribute = factor(
        attribute,
        levels = attribute_order
      ),

      label = factor(
        label,
        levels = rev(
          label_order
        )
      )
    )

  write_csv_safely(
    clogit_plot_df,
    "conditional_logit_coefficients.csv"
  )


  p_clogit_or <- ggplot(
    clogit_plot_df,
    aes(
      x = odds_ratio,
      y = label,
      shape = party_n,
      linetype = party_n,
      group = party_n
    )
  ) +
    geom_vline(
      xintercept = 1,
      linetype = "dashed",
      linewidth = 0.45,
      color = "grey35"
    ) +
    geom_errorbarh(
      aes(
        xmin = odds_ratio_low,
        xmax = odds_ratio_high
      ),
      position = position_dodge(
        width = 0.72
      ),
      height = 0.15,
      linewidth = 0.45,
      color = "black"
    ) +
    geom_point(
      position = position_dodge(
        width = 0.72
      ),
      size = 2.4,
      stroke = 0.7,
      color = "black"
    ) +
    scale_x_log10(
      breaks = scales::log_breaks(
        n = 8
      )
    ) +
    scale_shape_manual(
      values = c(
        "2選択肢" = 16,
        "3選択肢" = 17,
        "4選択肢" = 15,
        "5選択肢" = 1
      )
    ) +
    scale_linetype_manual(
      values = c(
        "2選択肢" = "solid",
        "3選択肢" = "dashed",
        "4選択肢" = "dotdash",
        "5選択肢" = "twodash"
      )
    ) +
    facet_grid(
      attribute ~ .,
      scales = "free_y",
      space = "free_y",
      switch = "y"
    ) +
    labs(
      x = "オッズ比",
      y = NULL,
      shape = "選択肢数",
      linetype = "選択肢数"
    ) +
    theme_bw(
      base_size = 12,
      base_family = figure_font_family
    ) +
    theme(
      legend.position = "bottom",
      panel.grid.major.y = element_blank(),
      panel.grid.minor = element_blank(),
      plot.title = element_text(
        face = "bold"
      ),
      strip.placement = "outside",
      strip.background = element_rect(
        fill = "grey92",
        color = "grey55"
      ),
      strip.text.y.left = element_text(
        angle = 0,
        face = "bold"
      ),
      axis.text.y = element_text(
        size = 8.5
      )
    )

  print(p_clogit_or)

  save_plot(
    "clogit_oddsratio_nocov.png",
    p_clogit_or,
    width = 10.5,
    height = 11.5
  )


  experimental_party_names <- as.character(
    party_levels_use
  )

  conjoint_match <- conjoint_all_cov %>%
    mutate(
      party_name_chr = as.character(party_name),
      
      support_party_valid = if_else(
        party_support_profile %in% experimental_party_names,
        party_support_profile,
        NA_character_
      ),
      
      party_match = case_when(
        is.na(support_party_valid) ~ NA_integer_,
        party_name_chr == support_party_valid ~ 1L,
        TRUE ~ 0L
      )
    ) %>%
    filter(
      !is.na(party_match)
    )

  party_match_sample <- conjoint_match %>%
    distinct(
      ID,
      party_n,
      support_party_valid
    ) %>%
    count(
      party_n,
      support_party_valid,
      name = "n_respondents"
    )

  write_csv_safely(
    party_match_sample,
    "party_match_sample.csv"
  )


  formula_party_match_overall <- as.formula(
    paste(
      "selected ~",
      paste(
        c(
          "party_name",
          "party_match",
          economic_attr_terms
        ),
        collapse = " + "
      )
    )
  )

  run_party_match_overall <- function(dat) {
    feols(
      formula_party_match_overall,
      data = dat,
      vcov = ~ ID
    )
  }

  models_party_match_by_n <- conjoint_match %>%
    split(.$party_n) %>%
    map(run_party_match_overall)

  m_party_match_interaction <- feols(
    selected ~
      party_n_f *
      party_match +
      party_name +
      gdp_growth +
      nikkei +
      cpi +
      unemployment,
    data = conjoint_match,
    vcov = ~ ID
  )

  capture.output(
    lapply(
      models_party_match_by_n,
      summary
    ),
    file = file.path(
      output_dir,
      "party_match_models_by_choice_number.txt"
    )
  )

  capture.output(
    summary(m_party_match_interaction),
    file = file.path(
      output_dir,
      "party_match_interaction_model.txt"
    )
  )

  extract_party_match_term <- function(model) {
    out <- tidy_fixest(model) %>%
      filter(term == "party_match")
    
    if (nrow(out) == 0) {
      return(
        tibble(
          term = "party_match",
          estimate = NA_real_,
          std.error = NA_real_,
          statistic = NA_real_,
          p.value = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_
        )
      )
    }
    
    out
  }

  party_match_coef_df <- imap_dfr(
    models_party_match_by_n,
    ~ extract_party_match_term(.x) %>%
      mutate(
        support_group = "全体",
        support_group_label = "全体",
        party_n = as.integer(.y)
      )
  ) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      
      party_n_label = factor(
        party_n,
        levels = 2:5,
        labels = c(
          "2選択肢",
          "3選択肢",
          "4選択肢",
          "5選択肢"
        )
      )
    )

  write_csv_safely(
    party_match_coef_df,
    "party_match_coefficients.csv"
  )


  target_support_groups <- c(
    "自由民主党",
    "中道改革連合",
    "立憲民主党",
    "参政党"
  )

  target_support_labels <- c(
    "自由民主党"   = "自民党支持者",
    "中道改革連合" = "中道改革支持者",
    "立憲民主党"   = "立憲支持者",
    "参政党"       = "参政党支持者"
  )

  party_match_subgroup_sample <- conjoint_match %>%
    distinct(
      ID,
      party_n,
      support_party_valid
    ) %>%
    filter(
      support_party_valid %in% target_support_groups
    ) %>%
    count(
      support_party_valid,
      party_n,
      name = "n_respondents"
    ) %>%
    mutate(
      support_group_label = recode(
        support_party_valid,
        !!!target_support_labels
      )
    )

  write_csv_safely(
    party_match_subgroup_sample,
    "party_match_subgroup_sample.csv"
  )

  support_group_total_n <- conjoint_match %>%
    distinct(
      ID,
      support_party_valid
    ) %>%
    filter(
      support_party_valid %in% target_support_groups
    ) %>%
    count(
      support_party_valid,
      name = "n_total"
    )

  formula_party_match_subgroup <- as.formula(
    paste(
      "selected ~",
      paste(
        c(
          "party_match",
          economic_attr_terms
        ),
        collapse = " + "
      )
    )
  )

  run_party_match_subgroup <- function(dat) {
    feols(
      formula_party_match_subgroup,
      data = dat,
      vcov = ~ ID
    )
  }

  estimate_party_match_subgroup <- function(
      dat,
      support_group_value
  ) {
    map_dfr(
      2:5,
      function(n_value) {
        
        dat_n <- dat %>%
          filter(
            party_n == n_value,
            support_party_valid == support_group_value
          )
        
        n_ids <- n_distinct(dat_n$ID)
        
        if (nrow(dat_n) == 0 || n_ids == 0) {
          return(
            tibble(
              term = "party_match",
              estimate = NA_real_,
              std.error = NA_real_,
              statistic = NA_real_,
              p.value = NA_real_,
              conf.low = NA_real_,
              conf.high = NA_real_,
              support_group = support_group_value,
              support_group_label = unname(
                target_support_labels[[support_group_value]]
              ),
              party_n = n_value,
              n_ids = n_ids
            )
          )
        }
        
        model_n <- tryCatch(
          run_party_match_subgroup(dat_n),
          error = function(e) NULL
        )
        
        if (is.null(model_n)) {
          return(
            tibble(
              term = "party_match",
              estimate = NA_real_,
              std.error = NA_real_,
              statistic = NA_real_,
              p.value = NA_real_,
              conf.low = NA_real_,
              conf.high = NA_real_,
              support_group = support_group_value,
              support_group_label = unname(
                target_support_labels[[support_group_value]]
              ),
              party_n = n_value,
              n_ids = n_ids
            )
          )
        }
        
        extract_party_match_term(model_n) %>%
          mutate(
            support_group = support_group_value,
            support_group_label = unname(
              target_support_labels[[support_group_value]]
            ),
            party_n = n_value,
            n_ids = n_ids
          )
      }
    )
  }

  party_match_subgroup_coef_df <- map_dfr(
    target_support_groups,
    ~ estimate_party_match_subgroup(
      conjoint_match,
      .x
    )
  ) %>%
    left_join(
      support_group_total_n,
      by = c(
        "support_group" = "support_party_valid"
      )
    ) %>%
    mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      party_n_label = factor(
        party_n,
        levels = 2:5,
        labels = c(
          "2選択肢",
          "3選択肢",
          "4選択肢",
          "5選択肢"
        )
      )
    )

  write_csv_safely(
    party_match_subgroup_coef_df,
    "party_match_subgroup_coefficients.csv"
  )


  party_match_plot_df_all <- bind_rows(
    party_match_coef_df %>%
      mutate(panel = "overall"),
    party_match_subgroup_coef_df %>%
      mutate(panel = "subgroup")
  ) %>%
    filter(
      is.finite(estimate_pp),
      is.finite(conf.low_pp),
      is.finite(conf.high_pp)
    )

  if (nrow(party_match_plot_df_all) == 0) {
    stop("Check data")
  }

  y_range_match <- range(
    c(
      party_match_plot_df_all$conf.low_pp,
      party_match_plot_df_all$conf.high_pp
    ),
    na.rm = TRUE
  )

  y_span_match <- diff(y_range_match)

  if (!is.finite(y_span_match) || y_span_match <= 0) {
    y_span_match <- 5
  }

  y_pad_match <- max(1.2, 0.10 * y_span_match)

  y_limits_match <- c(
    y_range_match[1] - y_pad_match,
    y_range_match[2] + y_pad_match
  )


  theme_party_match_bw <- theme_bw(
    base_size = 12,
    base_family = figure_font_family
  ) +
    theme(
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(
        linewidth = 0.30,
        color = "grey88"
      ),
      panel.border = element_rect(
        linewidth = 0.65,
        color = "black"
      ),
      axis.text = element_text(color = "black"),
      axis.title = element_text(color = "black"),
      plot.title = element_text(
        face = "bold"
      ),
      plot.subtitle = element_text(
        size = rel(0.92)
      ),
      plot.margin = margin(
        8, 10, 8, 8
      )
    )


  make_party_match_panel_plot <- function(
      dat,
      panel_title,
      panel_subtitle = NULL,
      base_size = 11,
      show_y_title = TRUE,
      show_x_title = TRUE
  ) {
    ggplot(
      dat,
      aes(
        x = party_n,
        y = estimate_pp
      )
    ) +
      geom_line(
        linewidth = 0.80,
        color = "black",
        na.rm = TRUE
      ) +
      geom_errorbar(
        aes(
          ymin = conf.low_pp,
          ymax = conf.high_pp
        ),
        width = 0.075,
        linewidth = 0.80,
        color = "black",
        na.rm = TRUE
      ) +
      geom_label(
        aes(
          label = sprintf("%.1f pp", estimate_pp)
        ),
        size = 3.45,
        family = figure_font_family,
        label.size = 0,
        label.padding = unit(
          0.12,
          "lines"
        ),
        fill = "white",
        color = "black",
        na.rm = TRUE
      ) +
      scale_x_continuous(
        breaks = 2:5,
        labels = paste0(
          2:5,
          "選択肢"
        ),
        limits = c(1.72, 5.28)
      ) +
      scale_y_continuous(
        labels = function(x) {
          paste0(x, " pp")
        },
        breaks = scales::pretty_breaks(n = 6),
        expand = expansion(
          mult = c(0.05, 0.08)
        )
      ) +
      coord_cartesian(
        ylim = y_limits_match
      ) +
      labs(
        title = panel_title,
        subtitle = panel_subtitle,
        x = if (show_x_title) "選択肢数" else NULL,
        y = if (show_y_title) "一致した場合の選択確率の変化" else NULL
      ) +
      theme_bw(
        base_size = base_size,
        base_family = figure_font_family
      ) +
      theme_party_match_bw +
      theme(
        plot.title = element_text(
          face = "bold"
        ),
        axis.title.x = if (show_x_title) element_text() else element_blank(),
        axis.title.y = if (show_y_title) element_text() else element_blank()
      )
  }

  make_support_group_title <- function(
      support_group_value
  ) {
    n_value <- support_group_total_n %>%
      filter(
        support_party_valid == support_group_value
      ) %>%
      pull(n_total)
    
    if (length(n_value) == 0 || is.na(n_value)) {
      n_value <- 0
    }
    
    paste0(
      target_support_labels[[support_group_value]],
      "\n(n=",
      scales::comma(n_value),
      ")"
    )
  }


  p_party_match_overall <- make_party_match_panel_plot(
    party_match_coef_df,
    panel_title = NULL,
    panel_subtitle =
      "上段は全体、下段は支持政党別(自民・中道改革・立憲・参政)。政党名と経済属性を統制した線形確率モデル。",
    base_size = 12,
    show_y_title = TRUE,
    show_x_title = TRUE
  )


  p_party_match_ldp <- make_party_match_panel_plot(
    party_match_subgroup_coef_df %>%
      filter(support_group == "自由民主党"),
    panel_title = make_support_group_title("自由民主党"),
    base_size = 10,
    show_y_title = TRUE,
    show_x_title = TRUE
  )

  p_party_match_chr <- make_party_match_panel_plot(
    party_match_subgroup_coef_df %>%
      filter(support_group == "中道改革連合"),
    panel_title = make_support_group_title("中道改革連合"),
    base_size = 10,
    show_y_title = FALSE,
    show_x_title = TRUE
  )

  p_party_match_cdp <- make_party_match_panel_plot(
    party_match_subgroup_coef_df %>%
      filter(support_group == "立憲民主党"),
    panel_title = make_support_group_title("立憲民主党"),
    base_size = 10,
    show_y_title = FALSE,
    show_x_title = TRUE
  )

  p_party_match_sansei <- make_party_match_panel_plot(
    party_match_subgroup_coef_df %>%
      filter(support_group == "参政党"),
    panel_title = make_support_group_title("参政党"),
    base_size = 10,
    show_y_title = FALSE,
    show_x_title = TRUE
  )

  p_party_match_bottom <-
    p_party_match_ldp +
    p_party_match_chr +
    p_party_match_cdp +
    p_party_match_sansei +
    patchwork::plot_layout(ncol = 4)

  p_party_match <-
    p_party_match_overall /
    p_party_match_bottom +
    patchwork::plot_layout(
      heights = c(1.25, 1)
    )

  print(p_party_match)

  save_plot(
    "party_match_effect_combined.png",
    p_party_match,
    width = 14,
    height = 8.8
  )


  relative_cue_map <- c(
    party_name = "party",
    gdp_growth = "economic",
    nikkei = "economic",
    cpi = "economic",
    unemployment = "economic"
  )

  mean_absolute_pairwise_difference <- function(x) {
    x <- x[is.finite(x)]

    if (length(x) < 2) {
      return(NA_real_)
    }

    pairwise_differences <- combn(
      x,
      2,
      FUN = function(z) abs(z[1] - z[2])
    )

    mean(pairwise_differences)
  }

  linear_slope <- function(y, x) {
    keep <- is.finite(y) & is.finite(x)
    y <- y[keep]
    x <- x[keep]

    if (length(y) < 2 || length(unique(x)) < 2) {
      return(NA_real_)
    }

    unname(coef(lm(y ~ x))[2])
  }

  bootstrap_two_sided_p <- function(x) {
    x <- x[is.finite(x)]
    B_valid <- length(x)

    if (B_valid == 0) {
      return(NA_real_)
    }

    p_lower <- (1 + sum(x <= 0)) / (B_valid + 1)
    p_upper <- (1 + sum(x >= 0)) / (B_valid + 1)

    min(1, 2 * min(p_lower, p_upper))
  }

  safe_quantile <- function(x, probability) {
    x <- x[is.finite(x)]

    if (length(x) == 0) {
      return(NA_real_)
    }

    unname(
      quantile(
        x,
        probs = probability,
        type = 6,
        na.rm = TRUE
      )
    )
  }

  prepare_relative_cue_analysis <- function(data, cue_map) {
    attributes <- names(cue_map)

    required_columns <- c(
      "ID",
      "party_n",
      "selected",
      attributes
    )

    missing_columns <- setdiff(
      required_columns,
      names(data)
    )

    if (length(missing_columns) > 0) {
      stop("Check relative weight")
    }

    if (!all(unname(cue_map) %in% c("party", "economic"))) {
      stop("Check relative weight")
    }

    analysis_data <- data %>%
      select(
        ID,
        party_n,
        selected,
        all_of(attributes)
      ) %>%
      mutate(
        ID = as.character(ID),
        party_n = as.integer(as.character(party_n)),
        selected = as.integer(selected),
        across(
          all_of(attributes),
          as.character
        )
      ) %>%
      filter(
        !is.na(ID),
        party_n %in% 2:5,
        selected %in% c(0L, 1L)
      )

    observed_conditions <- sort(
      unique(analysis_data$party_n)
    )

    if (!identical(observed_conditions, 2:5)) {
      stop("Check")
    }

    long_data <- analysis_data %>%
      pivot_longer(
        cols = all_of(attributes),
        names_to = "attribute",
        values_to = "level"
      ) %>%
      filter(
        !is.na(level),
        level != ""
      )

    expected_cells <- long_data %>%
      distinct(
        attribute,
        level
      ) %>%
      mutate(
        attribute_order = match(
          attribute,
          attributes
        )
      ) %>%
      arrange(
        attribute_order,
        attribute,
        level
      ) %>%
      select(-attribute_order) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    respondent_cell <- long_data %>%
      group_by(
        party_n,
        ID,
        attribute,
        level
      ) %>%
      summarise(
        y_sum = sum(selected),
        n_obs = n(),
        .groups = "drop"
      ) %>%
      mutate(
        cell_key = paste(
          attribute,
          level,
          sep = "\r"
        )
      )

    condition_objects <- lapply(
      2:5,
      function(n_value) {
        condition_data <- respondent_cell %>%
          filter(
            party_n == n_value
          )

        id_values <- sort(
          unique(condition_data$ID)
        )
        n_ids <- length(id_values)
        n_cells <- nrow(expected_cells)

        if (n_ids == 0) {
          stop("Check")
        }

        y_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        n_matrix <- matrix(
          0,
          nrow = n_ids,
          ncol = n_cells,
          dimnames = list(
            id_values,
            expected_cells$cell_key
          )
        )

        row_index <- match(
          condition_data$ID,
          id_values
        )
        column_index <- match(
          condition_data$cell_key,
          expected_cells$cell_key
        )

        y_matrix[cbind(row_index, column_index)] <-
          condition_data$y_sum
        n_matrix[cbind(row_index, column_index)] <-
          condition_data$n_obs

        if (any(colSums(n_matrix) == 0)) {
          missing_cells <- expected_cells$cell_key[
            colSums(n_matrix) == 0
          ]

          stop("Check attributes")
        }

        list(
          party_n = n_value,
          ids = id_values,
          cell_info = expected_cells,
          y_matrix = y_matrix,
          n_matrix = n_matrix
        )
      }
    )

    names(condition_objects) <- as.character(2:5)

    list(
      cue_map = cue_map,
      attributes = attributes,
      conditions = condition_objects
    )
  }

  estimate_relative_cue_indices <- function(
      prepared,
      cluster_weights = NULL
  ) {
    condition_results <- lapply(
      names(prepared$conditions),
      function(condition_name) {
        object <- prepared$conditions[[condition_name]]

        if (is.null(cluster_weights)) {
          weights <- rep(
            1,
            length(object$ids)
          )
        } else {
          weights <- cluster_weights[[condition_name]]
        }

        if (length(weights) != length(object$ids)) {
          stop("Check")
        }

        numerator <- as.numeric(
          crossprod(
            weights,
            object$y_matrix
          )
        )

        denominator <- as.numeric(
          crossprod(
            weights,
            object$n_matrix
          )
        )

        if (any(denominator <= 0)) {
          stop("Check attributes")
        }

        marginal_means <- numerator / denominator

        mm_table <- object$cell_info %>%
          transmute(
            party_n = object$party_n,
            attribute,
            level,
            marginal_mean = marginal_means
          )

        attribute_table <- mm_table %>%
          group_by(
            party_n,
            attribute
          ) %>%
          summarise(
            importance_pairwise =
              mean_absolute_pairwise_difference(
                marginal_mean
              ),
            n_levels = n(),
            .groups = "drop"
          ) %>%
          mutate(
            cue_family = unname(
              prepared$cue_map[attribute]
            ),
            baseline_selection_probability = 1 / party_n,
            importance_pairwise_adjusted =
              importance_pairwise /
                baseline_selection_probability
          )

        cue_table_long <- attribute_table %>%
          group_by(
            party_n,
            cue_family
          ) %>%
          summarise(
            importance_pairwise = mean(
              importance_pairwise,
              na.rm = TRUE
            ),
            importance_pairwise_adjusted = mean(
              importance_pairwise_adjusted,
              na.rm = TRUE
            ),
            .groups = "drop"
          )

        party_table <- cue_table_long %>%
          filter(
            cue_family == "party"
          ) %>%
          transmute(
            party_n,
            party_importance_pairwise =
              importance_pairwise,
            party_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        economic_table <- cue_table_long %>%
          filter(
            cue_family == "economic"
          ) %>%
          transmute(
            party_n,
            economic_importance_pairwise =
              importance_pairwise,
            economic_importance_pairwise_adjusted =
              importance_pairwise_adjusted
          )

        cue_table <- full_join(
          party_table,
          economic_table,
          by = "party_n"
        ) %>%
          mutate(
            baseline_selection_probability = 1 / party_n,

            total_importance_pairwise =
              party_importance_pairwise +
              economic_importance_pairwise,

            total_importance_pairwise_adjusted =
              party_importance_pairwise_adjusted +
              economic_importance_pairwise_adjusted,

            relative_party_weight_pairwise = if_else(
              total_importance_pairwise > 0,
              party_importance_pairwise /
                total_importance_pairwise,
              NA_real_
            ),

            relative_economic_weight_pairwise =
              1 - relative_party_weight_pairwise,

            relative_party_weight_pairwise_adjusted = if_else(
              total_importance_pairwise_adjusted > 0,
              party_importance_pairwise_adjusted /
                total_importance_pairwise_adjusted,
              NA_real_
            ),

            relative_economic_weight_pairwise_adjusted =
              1 - relative_party_weight_pairwise_adjusted,

            adjustment_identity_difference =
              relative_party_weight_pairwise_adjusted -
                relative_party_weight_pairwise
          )

        if (
          any(
            abs(cue_table$adjustment_identity_difference) > 1e-10,
            na.rm = TRUE
          )
        ) {
          stop("Check relative weight")
        }

        list(
          marginal_means = mm_table,
          attribute_importance = attribute_table,
          cue_importance = cue_table
        )
      }
    )

    list(
      marginal_means = bind_rows(
        lapply(
          condition_results,
          function(x) x$marginal_means
        )
      ),
      attribute_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$attribute_importance
        )
      ),
      cue_importance = bind_rows(
        lapply(
          condition_results,
          function(x) x$cue_importance
        )
      ) %>%
        arrange(party_n)
    )
  }

  estimate_relative_cue_slopes <- function(cue_importance) {
    cue_importance <- cue_importance %>%
      arrange(party_n)

    if (!identical(cue_importance$party_n, 2:5)) {
      stop("Check relative weight")
    }

    x <- cue_importance$party_n

    c(
      relative_party_weight_pairwise =
        linear_slope(
          cue_importance$relative_party_weight_pairwise,
          x
        ),

      party_importance_pairwise =
        linear_slope(
          cue_importance$party_importance_pairwise,
          x
        ),

      economic_importance_pairwise =
        linear_slope(
          cue_importance$economic_importance_pairwise,
          x
        ),

      party_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$party_importance_pairwise_adjusted,
          x
        ),

      economic_importance_pairwise_adjusted =
        linear_slope(
          cue_importance$economic_importance_pairwise_adjusted,
          x
        )
    )
  }

  run_relative_cue_bootstrap <- function(
      prepared,
      B,
      seed,
      progress_every = 100
  ) {
    set.seed(seed)

    condition_results <- vector(
      "list",
      B
    )

    slope_names <- c(
      "relative_party_weight_pairwise",
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted"
    )

    slope_matrix <- matrix(
      NA_real_,
      nrow = B,
      ncol = length(slope_names),
      dimnames = list(
        NULL,
        slope_names
      )
    )

    for (b in seq_len(B)) {
      cluster_weights <- lapply(
        prepared$conditions,
        function(object) {
          n_ids <- length(object$ids)

          sampled_positions <- sample.int(
            n = n_ids,
            size = n_ids,
            replace = TRUE
          )

          tabulate(
            sampled_positions,
            nbins = n_ids
          )
        }
      )

      bootstrap_estimates <- estimate_relative_cue_indices(
        prepared = prepared,
        cluster_weights = cluster_weights
      )

      condition_results[[b]] <-
        bootstrap_estimates$cue_importance %>%
        select(
          party_n,
          party_importance_pairwise,
          economic_importance_pairwise,
          party_importance_pairwise_adjusted,
          economic_importance_pairwise_adjusted,
          relative_party_weight_pairwise
        ) %>%
        mutate(
          bootstrap_replication = b,
          .before = 1
        )

      slope_matrix[b, ] <- estimate_relative_cue_slopes(
        bootstrap_estimates$cue_importance
      )

      if (
        progress_every > 0 &&
        (b %% progress_every == 0 || b == B)
      ) {
        message("Bootstrap: ", b, "/", B)
      }
    }

    list(
      condition_estimates = bind_rows(
        condition_results
      ),
      slopes = as_tibble(
        slope_matrix
      ) %>%
        mutate(
          bootstrap_replication = row_number(),
          .before = 1
        )
    )
  }

  summarise_condition_intervals <- function(
      observed_cue_importance,
      bootstrap_condition_results
  ) {
    statistics <- c(
      "party_importance_pairwise",
      "economic_importance_pairwise",
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted",
      "relative_party_weight_pairwise"
    )

    observed_long <- observed_cue_importance %>%
      select(
        party_n,
        all_of(statistics)
      ) %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "estimate"
      )

    bootstrap_long <- bootstrap_condition_results %>%
      pivot_longer(
        cols = all_of(statistics),
        names_to = "statistic",
        values_to = "value"
      ) %>%
      group_by(
        party_n,
        statistic
      ) %>%
      summarise(
        conf_low = safe_quantile(
          value,
          0.025
        ),
        conf_high = safe_quantile(
          value,
          0.975
        ),
        .groups = "drop"
      )

    observed_long %>%
      left_join(
        bootstrap_long,
        by = c(
          "party_n",
          "statistic"
        )
      )
  }

  summarise_slope_inference <- function(
      observed_slopes,
      bootstrap_slopes
  ) {
    statistic_names <- names(observed_slopes)

    map_dfr(
      statistic_names,
      function(statistic_name) {
        bootstrap_values <- bootstrap_slopes[[statistic_name]]
        bootstrap_values <- bootstrap_values[
          is.finite(bootstrap_values)
        ]

        expected_direction <- case_when(
          statistic_name ==
            "economic_importance_pairwise" ~ "negative",
          statistic_name %in% c(
            "party_importance_pairwise",
            "relative_party_weight_pairwise",
            "party_importance_pairwise_adjusted"
          ) ~ "positive",
          TRUE ~ "none"
        )

        analysis_role <- case_when(
          statistic_name %in% c(
            "party_importance_pairwise_adjusted",
            "economic_importance_pairwise_adjusted"
          ) ~ "exploratory_choice_set_adjusted",
          statistic_name == "relative_party_weight_pairwise" ~
            "derived_relative_share",
          TRUE ~ "manuscript_primary_unadjusted"
        )

        estimate <- unname(
          observed_slopes[[statistic_name]]
        )

        tibble(
          study = "Study 3",
          statistic = statistic_name,
          estimate = estimate,
          conf_low = safe_quantile(
            bootstrap_values,
            0.025
          ),
          conf_high = safe_quantile(
            bootstrap_values,
            0.975
          ),
          p_value_two_sided =
            bootstrap_two_sided_p(
              bootstrap_values
            ),
          expected_direction = expected_direction,
          analysis_role = analysis_role,
          estimate_in_expected_direction = case_when(
            expected_direction == "positive" ~ estimate > 0,
            expected_direction == "negative" ~ estimate < 0,
            TRUE ~ NA
          )
        )
      }
    )
  }

  relative_cue_prepared <- prepare_relative_cue_analysis(
    data = conjoint_all_m,
    cue_map = relative_cue_map
  )

  relative_cue_observed <- estimate_relative_cue_indices(
    prepared = relative_cue_prepared
  )

  relative_cue_observed_slopes <- estimate_relative_cue_slopes(
    relative_cue_observed$cue_importance
  )

  write_csv_safely(
    relative_cue_observed$marginal_means,
    "study3_relative_cue_marginal_means.csv"
  )

  write_csv_safely(
    relative_cue_observed$attribute_importance,
    "study3_relative_cue_attribute_importance.csv"
  )

  write_csv_safely(
    relative_cue_observed$cue_importance,
    "study3_relative_cue_importance_and_weight.csv"
  )

  relative_condition_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study3_relative_cue_condition_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  relative_slope_bootstrap_file <- file.path(
    output_dir,
    paste0(
      "study3_relative_cue_slope_bootstrap_",
      unified_config$cue_importance_metric_version,
      "_B",
      relative_cue_bootstrap_B,
      ".csv"
    )
  )

  use_saved_relative_bootstrap <-
    !rerun_relative_cue_bootstrap &&
    file.exists(relative_condition_bootstrap_file) &&
    file.exists(relative_slope_bootstrap_file)

  if (use_saved_relative_bootstrap) {
    message("Bootstrap cache")

    relative_cue_condition_bootstrap <- readr::read_csv(
      relative_condition_bootstrap_file,
      show_col_types = FALSE
    )

    relative_cue_slope_bootstrap <- readr::read_csv(
      relative_slope_bootstrap_file,
      show_col_types = FALSE
    )

    saved_B_condition <- n_distinct(
      relative_cue_condition_bootstrap$bootstrap_replication
    )
    saved_B_slope <- n_distinct(
      relative_cue_slope_bootstrap$bootstrap_replication
    )

    if (
      saved_B_condition != relative_cue_bootstrap_B ||
      saved_B_slope != relative_cue_bootstrap_B
    ) {
      message("Bootstrap cache")
      use_saved_relative_bootstrap <- FALSE
    }
  }

  if (!use_saved_relative_bootstrap) {
    relative_cue_bootstrap <- run_relative_cue_bootstrap(
      prepared = relative_cue_prepared,
      B = relative_cue_bootstrap_B,
      seed = relative_cue_bootstrap_seed,
      progress_every = relative_cue_bootstrap_progress_every
    )

    relative_cue_condition_bootstrap <-
      relative_cue_bootstrap$condition_estimates

    relative_cue_slope_bootstrap <-
      relative_cue_bootstrap$slopes

    readr::write_csv(
      relative_cue_condition_bootstrap,
      relative_condition_bootstrap_file
    )

    readr::write_csv(
      relative_cue_slope_bootstrap,
      relative_slope_bootstrap_file
    )
  }

  relative_cue_condition_intervals <- summarise_condition_intervals(
    observed_cue_importance =
      relative_cue_observed$cue_importance,
    bootstrap_condition_results =
      relative_cue_condition_bootstrap
  )

  relative_cue_slope_inference <- summarise_slope_inference(
    observed_slopes =
      relative_cue_observed_slopes,
    bootstrap_slopes =
      relative_cue_slope_bootstrap
  )

  write_csv_safely(
    relative_cue_condition_intervals,
    "study3_relative_cue_condition_intervals.csv"
  )

  write_csv_safely(
    relative_cue_slope_inference,
    "study3_relative_cue_slope_inference.csv"
  )

  relative_cue_primary_result <- relative_cue_slope_inference %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    )

  cat("\nStudy 3:相対比重の線形傾向\n")
  print(relative_cue_primary_result)


  relative_x_offset <- 0.075

  relative_panel_a_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise",
        "economic_importance_pairwise"
      )
    ) %>%
    mutate(
      cue_family = recode(
        statistic,
        party_importance_pairwise = "政党名手がかり",
        economic_importance_pairwise = "経済手がかり"
      ),
      cue_family = factor(
        cue_family,
        levels = c(
          "政党名手がかり",
          "経済手がかり"
        )
      ),
      x_plot = case_when(
        cue_family == "政党名手がかり" ~
          party_n + relative_x_offset,
        cue_family == "経済手がかり" ~
          party_n - relative_x_offset,
        TRUE ~ as.numeric(party_n)
      ),
      value_label = sprintf(
        "%.3f",
        estimate
      )
    )

  relative_panel_b_data <- relative_cue_condition_intervals %>%
    filter(
      statistic ==
        "relative_party_weight_pairwise"
    ) %>%
    mutate(
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_adjusted_label_map <- relative_panel_a_data %>%
    distinct(
      statistic,
      cue_family
    ) %>%
    mutate(
      statistic = paste0(
        statistic,
        "_adjusted"
      ),
      cue_family = as.character(
        cue_family
      )
    )

  relative_panel_adjusted_data <- relative_cue_condition_intervals %>%
    filter(
      statistic %in% c(
        "party_importance_pairwise_adjusted",
        "economic_importance_pairwise_adjusted"
      )
    ) %>%
    left_join(
      relative_adjusted_label_map,
      by = "statistic"
    ) %>%
    mutate(
      cue_family = factor(
        cue_family,
        levels = levels(
          relative_panel_a_data$cue_family
        )
      ),
      x_plot = if_else(
        as.integer(cue_family) == 1L,
        party_n + relative_x_offset,
        party_n - relative_x_offset
      ),
      value_label = sprintf(
        "%.1f%%",
        100 * estimate
      )
    )

  relative_condition_suffix <- if (
    "政党名手がかり" %in%
      levels(relative_panel_a_data$cue_family)
  ) {
    "選択肢"
  } else {
    "政党"
  }

  relative_condition_axis_title <- if (
    relative_condition_suffix == "選択肢"
  ) {
    "政治経済状況の選択肢数"
  } else {
    "政党選択肢数"
  }

  relative_figure_font_family <- if (
    .Platform$OS.type == "windows"
  ) {
    "Yu Gothic"
  } else {
    "sans"
  }

  relative_theme_japanese_bw <- theme_bw(
    base_size = 12,
    base_family = relative_figure_font_family
  ) +
    theme(
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(
        linewidth = 0.30,
        color = "grey88"
      ),
      panel.border = element_rect(
        linewidth = 0.65,
        color = "black"
      ),
      axis.text = element_text(
        color = "black"
      ),
      axis.title = element_text(
        color = "black"
      ),
      plot.title = element_text(
        size = 12.5,
        face = "bold",
        hjust = 0
      ),
      plot.subtitle = element_text(
        size = 9.5,
        hjust = 0,
        margin = margin(
          b = 8
        )
      ),
      legend.position = "top",
      legend.justification = "center",
      legend.key.width = grid::unit(
        1.25,
        "cm"
      ),
      plot.margin = margin(
        8,
        10,
        8,
        8
      )
    )

  relative_panel_a <- ggplot(
    relative_panel_a_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = c(
        "政党名手がかり" = "solid",
        "経済手がかり" = "dashed"
      )
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "選択肢"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_number(
        accuracy = 0.005
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:両手がかりの絶対的重要度",
      subtitle = "",
      x = "政党選択肢数",
      y = "手がかり重要度",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_adjusted_linetypes <- setNames(
    c(
      "solid",
      "dashed"
    ),
    levels(
      relative_panel_adjusted_data$cue_family
    )
  )

  relative_panel_adjusted <- ggplot(
    relative_panel_adjusted_data,
    aes(
      x = x_plot,
      y = estimate,
      group = cue_family,
      linetype = cue_family
    )
  ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_linetype_manual(
      values = relative_adjusted_linetypes
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        relative_condition_suffix
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.07,
          0.10
        )
      )
    ) +
    labs(
      title = "A:選択肢数調整済み重要度",
      subtitle =
        "未調整重要度 ÷ 平均選択確率(1/選択肢数)",
      x = relative_condition_axis_title,
      y = "平均選択確率に対する水準間差",
      linetype = NULL
    ) +
    guides(
      linetype = guide_legend(
        override.aes = list(
          linewidth = 0.90
        )
      )
    ) +
    relative_theme_japanese_bw

  relative_b_range <- range(
    c(
      relative_panel_b_data$conf_low,
      relative_panel_b_data$conf_high,
      0.5
    ),
    na.rm = TRUE
  )

  relative_b_padding <- max(
    0.025,
    0.10 * diff(relative_b_range)
  )

  relative_b_lower <- max(
    0,
    floor(
      20 *
        (relative_b_range[1] - relative_b_padding)
    ) / 20
  )

  relative_b_upper <- min(
    1,
    ceiling(
      20 *
        (relative_b_range[2] + relative_b_padding)
    ) / 20
  )

  if (relative_b_lower >= relative_b_upper) {
    relative_b_lower <- max(
      0,
      relative_b_lower - 0.05
    )
    relative_b_upper <- min(
      1,
      relative_b_upper + 0.05
    )
  }

  relative_panel_b <- ggplot(
    relative_panel_b_data,
    aes(
      x = party_n,
      y = estimate
    )
  ) +
    geom_hline(
      yintercept = 0.5,
      linetype = "dashed",
      linewidth = 0.55,
      color = "black"
    ) +
    geom_line(
      linewidth = 0.80,
      color = "black"
    ) +
    geom_errorbar(
      aes(
        ymin = conf_low,
        ymax = conf_high
      ),
      width = 0.075,
      linewidth = 0.80,
      color = "black"
    ) +
    geom_label(
      aes(
        label = value_label
      ),
      size = 3.55,
      family = relative_figure_font_family,
      label.size = 0,
      label.padding = grid::unit(
        0.12,
        "lines"
      ),
      fill = "white",
      color = "black"
    ) +
    scale_x_continuous(
      breaks = 2:5,
      labels = paste0(
        2:5,
        "選択肢"
      ),
      limits = c(
        1.72,
        5.28
      )
    ) +
    scale_y_continuous(
      breaks = seq(
        relative_b_lower,
        relative_b_upper,
        by = 0.05
      ),
      labels = label_percent(
        accuracy = 1
      ),
      expand = expansion(
        mult = c(
          0.05,
          0.08
        )
      )
    ) +
    coord_cartesian(
      ylim = c(
        relative_b_lower,
        relative_b_upper
      )
    ) +
    labs(
      title = "B:相対的な政党名手がかりの比重",
      subtitle =
        "政党名手がかり重要度 ÷(政党名手がかり重要度+経済手がかり重要度)",
      x = "政党選択肢数",
      y = "相対的な政党名手がかり比重"
    ) +
    relative_theme_japanese_bw +
    theme(
      legend.position = "none"
    )

  relative_panel_c <- relative_panel_b +
    labs(
      title = paste0(
        "B:相対的な",
        levels(relative_panel_a_data$cue_family)[1],
        "の比重"
      )
    )

  figure_relative_weight_jp <- (
    relative_panel_a |
      relative_panel_b
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_jp
  )

  save_plot(
    "fig_study3_relative_cue_weight_jp_bw.png",
    figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      "fig_study3_relative_cue_weight_jp_bw.pdf"
    ),
    plot = figure_relative_weight_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  figure_relative_weight_adjusted_jp <- (
    relative_panel_adjusted |
      relative_panel_c
  ) +
    patchwork::plot_layout(
      widths = c(
        1,
        1
      )
    )

  print(
    figure_relative_weight_adjusted_jp
  )

  relative_adjusted_figure_stub <- paste0(
    "fig_study",
    stringr::str_extract(
      study_label,
      "[123]"
    ),
    "_relative_cue_weight_choice_set_adjusted_jp_bw"
  )

  save_plot(
    paste0(
      relative_adjusted_figure_stub,
      ".png"
    ),
    figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    dpi = 400
  )

  ggsave(
    filename = file.path(
      output_dir,
      paste0(
        relative_adjusted_figure_stub,
        ".pdf"
      )
    ),
    plot = figure_relative_weight_adjusted_jp,
    width = 11.2,
    height = 5.4,
    device = grDevices::cairo_pdf,
    bg = "white"
  )

  relative_cue_results <- list(
    prepared = relative_cue_prepared,
    marginal_means =
      relative_cue_observed$marginal_means,
    attribute_importance =
      relative_cue_observed$attribute_importance,
    cue_importance =
      relative_cue_observed$cue_importance,
    observed_slopes =
      relative_cue_observed_slopes,
    condition_bootstrap =
      relative_cue_condition_bootstrap,
    slope_bootstrap =
      relative_cue_slope_bootstrap,
    condition_intervals =
      relative_cue_condition_intervals,
    slope_inference =
      relative_cue_slope_inference,
    primary_result =
      relative_cue_primary_result,
    plots = list(
      absolute_importance = relative_panel_a,
      choice_set_adjusted_importance =
        relative_panel_adjusted,
      relative_party_weight = relative_panel_b,
      relative_party_weight_panel_c =
        relative_panel_c,
      combined = figure_relative_weight_jp,
      combined_with_choice_set_adjustment =
        figure_relative_weight_adjusted_jp
    )
  )

  saveRDS(
    relative_cue_results,
    file = file.path(
      output_dir,
      "study3_relative_cue_results.rds"
    )
  )


  saveRDS(
    list(
      settings = list(
        data_file = data_file,
        require_initial_consent =
          require_initial_consent,
        require_final_consent =
          require_final_consent,
        require_attention_check =
          require_attention_check,
        require_manipulation_check =
          require_manipulation_check,
        require_all_five_tasks =
          require_all_five_tasks,
        party_reference =
          party_reference,
        party_levels_use =
          party_levels_use,
        relative_cue_bootstrap_B =
          relative_cue_bootstrap_B,
        relative_cue_bootstrap_seed =
          relative_cue_bootstrap_seed
      ),

      sample_flow = sample_flow,
      n_by_party = n_by_party,
      valid_ids = valid_ids,

      conjoint_all = conjoint_all,
      conjoint_all_m = conjoint_all_m,
      conjoint_all_cov = conjoint_all_cov,

      covar_id = covar_id,

      models_by_party_n_nocov =
        models_by_party_n_nocov,

      models_by_party_n_cov =
        models_by_party_n_cov,

      m_interaction =
        m_interaction,

      m_linear_trend =
        m_linear_trend,

      models_clogit_nocov =
        models_clogit_nocov,

      party_match = list(
        data = conjoint_match,
        models_by_n =
          models_party_match_by_n,
        interaction_model =
          m_party_match_interaction
      ),

      relative_cue = relative_cue_results,

      plots = list(
        amce_cov =
          p_amce_cov,
        amce_nocov =
          p_amce_nocov,
        interaction =
          p_interaction,
        linear_trend =
          p_linear_trend,
        heatmap =
          p_heat_amce,
        clogit_odds_ratio =
          p_clogit_or,
        party_match =
          p_party_match,
        relative_cue_weight =
          figure_relative_weight_jp,
        relative_cue_weight_choice_set_adjusted =
          figure_relative_weight_adjusted_jp
      )
    ),
    file = file.path(
      output_dir,
      "study3_analysis_objects.rds"
    )
  )

  capture.output(
    sessionInfo(),
    file = file.path(
      output_dir,
      "sessionInfo.txt"
    )
  )

  cat(
    "\nStudy 3の分析コードが最後まで完了しました。\n",
    "出力先: ",
    normalizePath(output_dir),
    "\n",
    sep = ""
  )

  environment()
})

A.5 補遺に関する各種の再現コード

# 補遺共通コード
unified_output_dir <- file.path(
  unified_config$output_root,
  "_working",
  "cross_study"
)
dir.create(unified_output_dir, showWarnings = FALSE, recursive = TRUE)

save_plot_both <- function(filename_stub, plot, width, height, dpi = 400) {
  png_file <- file.path(unified_output_dir, paste0(filename_stub, ".png"))
  pdf_file <- file.path(unified_output_dir, paste0(filename_stub, ".pdf"))
  
  ggplot2::ggsave(
    filename = png_file,
    plot = plot,
    width = width,
    height = height,
    dpi = dpi,
    bg = "white"
  )
  
  ggplot2::ggsave(
    filename = pdf_file,
    plot = plot,
    width = width,
    height = height,
    device = grDevices::cairo_pdf,
    bg = "white"
  )
  
  invisible(c(png = png_file, pdf = pdf_file))
}

write_csv_unified <- function(x, filename) {
  readr::write_csv(
    x,
    file.path(unified_output_dir, filename),
    na = ""
  )
}

safe_filename <- function(x) {
  x <- iconv(as.character(x), from = "", to = "ASCII//TRANSLIT")
  x[is.na(x) | x == ""] <- "group"
  x <- tolower(x)
  x <- gsub("[^a-z0-9]+", "_", x)
  x <- gsub("^_+|_+$", "", x)
  ifelse(x == "", "group", x)
}

tidy_fixest_unified <- function(model) {
  ct <- as.data.frame(fixest::coeftable(model))
  ct$term <- rownames(ct)
  
  estimate_col <- intersect(c("Estimate", "estimate"), names(ct))[1]
  se_col <- intersect(c("Std. Error", "Std. error", "std.error"), names(ct))[1]
  statistic_col <- intersect(c("t value", "z value", "statistic"), names(ct))[1]
  p_col <- intersect(c("Pr(>|t|)", "Pr(>|z|)", "p.value"), names(ct))[1]
  
  if (
    is.na(estimate_col) ||
    is.na(se_col) ||
    is.na(statistic_col) ||
    is.na(p_col)
  ) {
    stop("Check data")
  }
  
  tibble::as_tibble(ct) %>%
    dplyr::transmute(
      term = term,
      estimate = .data[[estimate_col]],
      std.error = .data[[se_col]],
      statistic = .data[[statistic_col]],
      p.value = .data[[p_col]],
      conf.low = estimate - 1.96 * std.error,
      conf.high = estimate + 1.96 * std.error
    )
}

study_specs <- list(
  study1 = list(
    study_id = "study1",
    study_label = "Study 1(2023年)",
    condition_label = "政党数",
    env = study1_env
  ),
  study2 = list(
    study_id = "study2",
    study_label = "Study 2(2026年)",
    condition_label = "政党数",
    env = study2_env
  ),
  study3 = list(
    study_id = "study3",
    study_label = "Study 3(2026年)",
    condition_label = "選択肢数",
    env = study3_env
  )
)

excluded_support_categories <- c(
  "その他",
  "わからない",
  "答えない",
  "答えたくない",
  "欠損・無回答"
)


# 補遺C関連コード
balance_variable_labels <- c(
  female_imp = "女性",
  female_miss = "性別:欠損",
  age_imp = "年齢",
  age_miss = "年齢:欠損",
  college_grad_imp = "4年制大学以上",
  college_grad_miss = "学歴:欠損",
  income_gross_log_imp = "世帯年収(対数)",
  income_gross_log_miss = "世帯年収:欠損",
  self_ideology_imp = "左右自己位置づけ",
  self_ideology_miss = "左右自己位置づけ:欠損"
)

make_balance_design <- function(study_spec) {
  env <- study_spec$env
  
  assignment <- env$conjoint_all %>%
    dplyr::distinct(ID, party_n) %>%
    dplyr::mutate(
      ID = as.character(ID),
      party_n = as.integer(as.character(party_n))
    )
  
  respondent <- env$covar_id %>%
    dplyr::mutate(ID = as.character(ID))
  
  dat <- assignment %>%
    dplyr::left_join(respondent, by = "ID")
  
  numeric_candidates <- c(
    "female_imp",
    "female_miss",
    "age_imp",
    "age_miss",
    "college_grad_imp",
    "college_grad_miss",
    "income_gross_log_imp",
    "income_gross_log_miss",
    "self_ideology_imp",
    "self_ideology_miss"
  )
  
  factor_candidates <- c(
    "party_support_f",
    "region"
  )
  
  numeric_use <- intersect(numeric_candidates, names(dat))
  factor_use <- intersect(factor_candidates, names(dat))
  
  design_source <- dat %>%
    dplyr::select(dplyr::all_of(c(numeric_use, factor_use)))
  
  if (length(factor_use) > 0) {
    design_source <- design_source %>%
      dplyr::mutate(
        dplyr::across(
          dplyr::all_of(factor_use),
          ~ forcats::fct_na_value_to_level(as.factor(.x), level = "欠損・無回答")
        )
      )
  }
  
  mm <- stats::model.matrix(
    stats::as.formula(
      paste0(
        "~ 0 + ",
        paste(names(design_source), collapse = " + ")
      )
    ),
    data = design_source
  )
  
  mm <- as.data.frame(mm, check.names = FALSE)
  
  keep <- vapply(
    mm,
    function(x) {
      x <- as.numeric(x)
      is.finite(stats::sd(x, na.rm = TRUE)) && stats::sd(x, na.rm = TRUE) > 0
    },
    logical(1)
  )
  
  mm <- mm[, keep, drop = FALSE]
  
  mm <- mm %>%
    dplyr::mutate(
      ID = dat$ID,
      party_n = dat$party_n,
      .before = 1
    )
  
  long <- mm %>%
    tidyr::pivot_longer(
      cols = -c(ID, party_n),
      names_to = "variable",
      values_to = "value"
    ) %>%
    dplyr::mutate(
      label = dplyr::case_when(
        variable %in% names(balance_variable_labels) ~
          unname(balance_variable_labels[variable]),
        stringr::str_detect(variable, "^party_support_f") ~
          paste0(
            "支持政党:",
            stringr::str_remove(variable, "^party_support_f")
          ),
        stringr::str_detect(variable, "^region") ~
          paste0(
            "地域:",
            stringr::str_remove(variable, "^region")
          ),
        TRUE ~ variable
      ),
      study_id = study_spec$study_id,
      study_label = study_spec$study_label
    )
  
  list(
    respondent = dat,
    matrix = mm,
    long = long,
    numeric_use = numeric_use,
    factor_use = factor_use
  )
}

pairwise_smd_multiarm <- function(balance_long) {
  groups <- sort(unique(balance_long$party_n))
  pairs <- utils::combn(groups, 2, simplify = FALSE)

  purrr::map_dfr(
    pairs,
    function(pair_value) {
      a <- pair_value[1]
      b <- pair_value[2]

      wide <- balance_long %>%
        dplyr::filter(party_n %in% c(a, b)) %>%
        dplyr::group_by(variable, label, party_n) %>%
        dplyr::summarise(
          mean = mean(value, na.rm = TRUE),
          sd = stats::sd(value, na.rm = TRUE),
          n = sum(!is.na(value)),
          .groups = "drop"
        ) %>%
        tidyr::pivot_wider(
          names_from = party_n,
          values_from = c(mean, sd, n),
          names_sep = "_"
        )

      wide %>%
        dplyr::transmute(
          variable = variable,
          label = label,
          condition_a = a,
          condition_b = b,
          comparison = paste0(a, " vs ", b),
          mean_a = .data[[paste0("mean_", a)]],
          mean_b = .data[[paste0("mean_", b)]],
          sd_a = .data[[paste0("sd_", a)]],
          sd_b = .data[[paste0("sd_", b)]],
          n_a = .data[[paste0("n_", a)]],
          n_b = .data[[paste0("n_", b)]],
          pooled_sd = sqrt((sd_a^2 + sd_b^2) / 2),
          smd = dplyr::if_else(
            is.finite(pooled_sd) & pooled_sd > 0,
            (mean_a - mean_b) / pooled_sd,
            NA_real_
          ),
          abs_smd = abs(smd)
        )
    }
  )
}

omnibus_balance_test <- function(balance_long) {
  balance_long %>%
    dplyr::group_by(variable, label) %>%
    dplyr::group_modify(
      ~ {
        dat <- .x %>%
          dplyr::filter(is.finite(value), !is.na(party_n))
        
        p_value <- tryCatch(
          {
            model <- stats::lm(value ~ factor(party_n), data = dat)
            as.numeric(stats::anova(model)[1, "Pr(>F)"])
          },
          error = function(e) NA_real_
        )
        
        tibble::tibble(p_value = p_value)
      }
    ) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(p_holm = stats::p.adjust(p_value, method = "holm"))
}

make_balance_outputs <- function(study_spec) {
  design <- make_balance_design(study_spec)
  long <- design$long
  pairwise <- pairwise_smd_multiarm(long)
  omnibus <- omnibus_balance_test(long)
  
  max_smd <- pairwise %>%
    dplyr::group_by(variable, label) %>%
    dplyr::summarise(
      max_abs_smd = dplyr::if_else(
        all(is.na(abs_smd)),
        NA_real_,
        max(abs_smd, na.rm = TRUE)
      ),
      mean_abs_smd = dplyr::if_else(
        all(is.na(abs_smd)),
        NA_real_,
        mean(abs_smd, na.rm = TRUE)
      ),
      .groups = "drop"
    )
  
  group_summary <- long %>%
    dplyr::group_by(variable, label, party_n) %>%
    dplyr::summarise(
      mean = mean(value, na.rm = TRUE),
      sd = stats::sd(value, na.rm = TRUE),
      n = sum(!is.na(value)),
      .groups = "drop"
    ) %>%
    tidyr::pivot_wider(
      names_from = party_n,
      values_from = c(mean, sd, n),
      names_glue = "{.value}_condition_{party_n}"
    ) %>%
    dplyr::left_join(max_smd, by = c("variable", "label")) %>%
    dplyr::left_join(omnibus, by = c("variable", "label")) %>%
    dplyr::arrange(dplyr::desc(max_abs_smd))
  
  write_csv_unified(
    pairwise,
    paste0(study_spec$study_id, "_assignment_balance_pairwise_smd.csv")
  )
  write_csv_unified(
    group_summary,
    paste0(study_spec$study_id, "_assignment_balance_summary.csv")
  )
  
  love_df <- pairwise %>%
    dplyr::left_join(max_smd, by = c("variable", "label")) %>%
    dplyr::mutate(
      label_ordered = stats::reorder(label, max_abs_smd)
    )
  
  p_love <- ggplot2::ggplot(
    love_df,
    ggplot2::aes(
      x = abs_smd,
      y = label_ordered
    )
  ) +
    ggplot2::geom_vline(
      xintercept = 0.10,
      linetype = "dashed",
      linewidth = 0.55
    ) +
    ggplot2::geom_point(
      alpha = 0.30,
      size = 1.4,
      position = ggplot2::position_jitter(height = 0.10, width = 0)
    ) +
    ggplot2::geom_point(
      data = max_smd %>%
        dplyr::mutate(label_ordered = stats::reorder(label, max_abs_smd)),
      ggplot2::aes(
        x = max_abs_smd,
        y = label_ordered
      ),
      inherit.aes = FALSE,
      shape = 21,
      fill = "white",
      size = 2.5,
      stroke = 0.8
    ) +
    ggplot2::scale_x_continuous(
      breaks = scales::pretty_breaks(n = 6),
      expand = ggplot2::expansion(mult = c(0, 0.05))
    ) +
    ggplot2::labs(
      x = "条件間の絶対標準化平均差(|SMD|)",
      y = NULL,
      subtitle = paste0(
        study_spec$study_label,
        ":各点は条件ペア、白抜き点は最大絶対SMD"
      ),
      caption = "破線は |SMD| = 0.10。多群無作為割付のため、2・3・4・5条件の全6ペアを比較。"
    ) +
    ggplot2::theme_bw(base_size = 11) +
    ggplot2::theme(
      panel.grid.minor = ggplot2::element_blank(),
      axis.text = ggplot2::element_text(color = "black"),
      plot.subtitle = ggplot2::element_text(face = "bold")
    )
  
  save_plot_both(
    paste0(study_spec$study_id, "_assignment_balance_love_plot"),
    p_love,
    width = 9.2,
    height = max(6.5, 0.23 * dplyr::n_distinct(love_df$label) + 2.5)
  )
  
  standardized_means <- long %>%
    dplyr::group_by(variable, label) %>%
    dplyr::mutate(
      overall_mean = mean(value, na.rm = TRUE),
      overall_sd = stats::sd(value, na.rm = TRUE),
      value_z = dplyr::if_else(
        is.finite(overall_sd) & overall_sd > 0,
        (value - overall_mean) / overall_sd,
        NA_real_
      )
    ) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(variable, label, party_n) %>%
    dplyr::summarise(
      mean_z = mean(value_z, na.rm = TRUE),
      .groups = "drop"
    )
  
  groups <- sort(unique(standardized_means$party_n))
  diagonal_df <- purrr::map_dfr(
    utils::combn(groups, 2, simplify = FALSE),
    function(pair_value) {
      a <- pair_value[1]
      b <- pair_value[2]
      
      standardized_means %>%
        dplyr::filter(party_n %in% c(a, b)) %>%
        tidyr::pivot_wider(
          names_from = party_n,
          values_from = mean_z,
          names_prefix = "condition_"
        ) %>%
        dplyr::mutate(
          condition_a = a,
          condition_b = b,
          comparison = paste0(a, " vs ", b),
          x_mean = .data[[paste0("condition_", a)]],
          y_mean = .data[[paste0("condition_", b)]],
          diagonal_deviation = y_mean - x_mean,
          abs_diagonal_deviation = abs(diagonal_deviation)
        )
    }
  )
  
  top_labels <- diagonal_df %>%
    dplyr::group_by(comparison) %>%
    dplyr::slice_max(
      order_by = abs_diagonal_deviation,
      n = 3,
      with_ties = FALSE
    ) %>%
    dplyr::ungroup()
  
  axis_limit <- max(
    abs(c(diagonal_df$x_mean, diagonal_df$y_mean)),
    na.rm = TRUE
  )
  axis_limit <- max(0.10, axis_limit * 1.15)
  
  p_diagonal <- ggplot2::ggplot(
    diagonal_df,
    ggplot2::aes(x = x_mean, y = y_mean)
  ) +
    ggplot2::geom_abline(
      intercept = 0,
      slope = 1,
      linewidth = 0.60,
      linetype = "dashed"
    ) +
    ggplot2::geom_hline(yintercept = 0, linewidth = 0.25) +
    ggplot2::geom_vline(xintercept = 0, linewidth = 0.25) +
    ggplot2::geom_point(shape = 21, fill = "white", size = 2.2) +
    ggplot2::geom_text(
      data = top_labels,
      ggplot2::aes(label = label),
      size = 2.6,
      check_overlap = TRUE,
      vjust = -0.7
    ) +
    ggplot2::facet_wrap(~ comparison, ncol = 3) +
    ggplot2::coord_equal(
      xlim = c(-axis_limit, axis_limit),
      ylim = c(-axis_limit, axis_limit)
    ) +
    ggplot2::labs(
      x = "左側条件の標準化共変量平均",
      y = "右側条件の標準化共変量平均",
      subtitle = paste0(
        study_spec$study_label,
        ":45度線からの乖離による割付バランス診断"
      ),
      caption = "各点は回答者共変量または支持政党・地域のダミー変数。45度線に近いほど条件間の構成が類似。"
    ) +
    ggplot2::theme_bw(base_size = 10.5) +
    ggplot2::theme(
      panel.grid.minor = ggplot2::element_blank(),
      strip.background = ggplot2::element_rect(fill = "white"),
      strip.text = ggplot2::element_text(face = "bold"),
      axis.text = ggplot2::element_text(color = "black")
    )
  
  write_csv_unified(
    diagonal_df,
    paste0(study_spec$study_id, "_assignment_balance_diagonal_data.csv")
  )
  
  save_plot_both(
    paste0(study_spec$study_id, "_assignment_balance_diagonal_plot"),
    p_diagonal,
    width = 11.5,
    height = 7.5
  )
  
  list(
    design = design,
    pairwise_smd = pairwise,
    summary = group_summary,
    love_plot = p_love,
    diagonal_data = diagonal_df,
    diagonal_plot = p_diagonal
  )
}

assignment_balance_results <- purrr::map(
  study_specs,
  make_balance_outputs
)


make_profile_randomization_outputs <- function(study_spec) {
  env <- study_spec$env
  attributes <- env$attr_terms
  
  randomization_long <- env$conjoint_all_m %>%
    dplyr::select(
      ID,
      party_n,
      task,
      profile,
      dplyr::all_of(attributes)
    ) %>%
    tidyr::pivot_longer(
      cols = dplyr::all_of(attributes),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    dplyr::mutate(
      level = as.character(level),
      party_n = as.integer(as.character(party_n))
    ) %>%
    dplyr::filter(!is.na(level), level != "")
  
  frequency <- randomization_long %>%
    dplyr::count(party_n, attribute, level, name = "observed_n") %>%
    dplyr::group_by(party_n, attribute) %>%
    dplyr::mutate(
      total_n = sum(observed_n),
      n_levels = dplyr::n(),
      observed_share = observed_n / total_n,
      expected_share = 1 / n_levels,
      deviation = observed_share - expected_share,
      abs_deviation = abs(deviation)
    ) %>%
    dplyr::ungroup()
  
  uniformity_tests <- frequency %>%
    dplyr::group_by(party_n, attribute) %>%
    dplyr::group_modify(
      ~ {
        test <- suppressWarnings(
          stats::chisq.test(
            x = .x$observed_n,
            p = rep(1 / nrow(.x), nrow(.x))
          )
        )
        tibble::tibble(
          chi_square = unname(test$statistic),
          df = unname(test$parameter),
          p_value = test$p.value,
          max_abs_share_deviation = max(.x$abs_deviation)
        )
      }
    ) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(p_holm = stats::p.adjust(p_value, method = "holm"))
  
  write_csv_unified(
    frequency,
    paste0(study_spec$study_id, "_profile_level_randomization_frequency.csv")
  )
  write_csv_unified(
    uniformity_tests,
    paste0(study_spec$study_id, "_profile_level_randomization_tests.csv")
  )
  
  top_frequency_labels <- frequency %>%
    dplyr::group_by(party_n, attribute) %>%
    dplyr::slice_max(abs_deviation, n = 1, with_ties = FALSE) %>%
    dplyr::ungroup()
  
  p_randomization <- ggplot2::ggplot(
    frequency,
    ggplot2::aes(
      x = expected_share,
      y = observed_share
    )
  ) +
    ggplot2::geom_abline(
      intercept = 0,
      slope = 1,
      linetype = "dashed",
      linewidth = 0.65
    ) +
    ggplot2::geom_point(
      ggplot2::aes(shape = factor(party_n)),
      size = 2.2,
      fill = "white"
    ) +
    ggplot2::geom_text(
      data = top_frequency_labels,
      ggplot2::aes(label = level),
      size = 2.4,
      check_overlap = TRUE,
      vjust = -0.7
    ) +
    ggplot2::facet_wrap(~ attribute, ncol = 3) +
    ggplot2::coord_equal() +
    ggplot2::labs(
      x = "設計上の期待比率",
      y = "観測比率",
      shape = study_spec$condition_label,
      subtitle = paste0(
        study_spec$study_label,
        ":属性水準の観測比率と期待比率"
      ),
      caption = "各点は属性水準×条件。45度線に近いほど属性水準の無作為提示が設計どおり。"
    ) +
    ggplot2::theme_bw(base_size = 10.5) +
    ggplot2::theme(
      panel.grid.minor = ggplot2::element_blank(),
      strip.background = ggplot2::element_rect(fill = "white"),
      strip.text = ggplot2::element_text(face = "bold"),
      legend.position = "bottom",
      axis.text = ggplot2::element_text(color = "black")
    )
  
  save_plot_both(
    paste0(study_spec$study_id, "_profile_randomization_diagonal_plot"),
    p_randomization,
    width = 11,
    height = ifelse(study_spec$study_id == "study3", 7.5, 8.5)
  )
  
  list(
    frequency = frequency,
    uniformity_tests = uniformity_tests,
    plot = p_randomization
  )
}

profile_randomization_results <- purrr::map(
  study_specs,
  make_profile_randomization_outputs
)


# 補遺H関連コード
make_term_label_table <- function(env) {
  if (exists("term_labels", envir = env, inherits = FALSE)) {
    out <- get("term_labels", envir = env)
    required <- c("term", "attribute", "label")
    if (all(required %in% names(out))) {
      return(out %>% dplyr::select(dplyr::any_of(c(required, "order"))))
    }
  }
  
  tibble::tibble(
    term = character(),
    attribute = character(),
    label = character(),
    order = integer()
  )
}

run_support_amce_heterogeneity <- function(study_spec) {
  env <- study_spec$env
  study_id <- study_spec$study_id
  study_label <- study_spec$study_label
  out_dir <- file.path(unified_output_dir, paste0(study_id, "_party_support"))
  dir.create(out_dir, showWarnings = FALSE, recursive = TRUE)
  
  support_id <- env$covar_id %>%
    dplyr::transmute(
      ID = as.character(ID),
      party_support_h = as.character(party_support_f)
    ) %>%
    dplyr::mutate(
      party_support_h = dplyr::na_if(party_support_h, "欠損・無回答")
    )
  
  dat <- env$conjoint_all_m %>%
    dplyr::mutate(
      ID = as.character(ID),
      party_n = as.integer(as.character(party_n))
    ) %>%
    dplyr::left_join(support_id, by = "ID") %>%
    dplyr::filter(
      !is.na(party_support_h),
      party_support_h != "",
      !party_support_h %in% excluded_support_categories
    )
  
  support_counts <- dat %>%
    dplyr::distinct(ID, party_n, party_support_h) %>%
    dplyr::count(party_support_h, party_n, name = "n_condition") %>%
    dplyr::group_by(party_support_h) %>%
    dplyr::mutate(
      n_total = sum(n_condition),
      min_condition_n = min(n_condition),
      conditions_observed = dplyr::n_distinct(party_n)
    ) %>%
    dplyr::ungroup()
  
  support_totals <- dat %>%
    dplyr::distinct(ID, party_support_h) %>%
    dplyr::count(party_support_h, name = "n_total_distinct")
  
  support_counts <- support_counts %>%
    dplyr::left_join(support_totals, by = "party_support_h") %>%
    dplyr::arrange(dplyr::desc(n_total_distinct), party_support_h)
  
  eligible_groups <- support_counts %>%
    dplyr::distinct(
      party_support_h,
      n_total_distinct,
      min_condition_n,
      conditions_observed
    ) %>%
    dplyr::filter(
      n_total_distinct >= unified_config$min_support_total_n,
      conditions_observed == 4
    ) %>%
    dplyr::pull(party_support_h)
  
  readr::write_csv(
    support_counts,
    file.path(out_dir, "party_support_sample_counts.csv"),
    na = ""
  )
  
  formula_subgroup <- stats::as.formula(
    paste(
      "selected ~",
      paste(env$attr_terms, collapse = " + ")
    )
  )
  
  estimate_one_cell <- function(group_value, n_value) {
    dat_cell <- dat %>%
      dplyr::filter(
        party_support_h == group_value,
        party_n == n_value
      )
    
    n_ids <- dplyr::n_distinct(dat_cell$ID)
    
    if (n_ids < unified_config$min_support_cell_n) {
      return(
        tibble::tibble(
          term = NA_character_,
          estimate = NA_real_,
          std.error = NA_real_,
          statistic = NA_real_,
          p.value = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_,
          party_support_h = group_value,
          party_n = n_value,
          n_ids = n_ids,
          status = "insufficient_cell_n"
        )
      )
    }
    
    model <- tryCatch(
      fixest::feols(
        formula_subgroup,
        data = dat_cell,
        vcov = ~ ID
      ),
      error = function(e) e
    )
    
    if (inherits(model, "error")) {
      return(
        tibble::tibble(
          term = NA_character_,
          estimate = NA_real_,
          std.error = NA_real_,
          statistic = NA_real_,
          p.value = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_,
          party_support_h = group_value,
          party_n = n_value,
          n_ids = n_ids,
          status = paste0("model_error: ", conditionMessage(model))
        )
      )
    }
    
    tidy_fixest_unified(model) %>%
      dplyr::mutate(
        party_support_h = group_value,
        party_n = n_value,
        n_ids = n_ids,
        status = "estimated"
      )
  }
  
  subgroup_coefficients <- purrr::map_dfr(
    eligible_groups,
    function(group_value) {
      purrr::map_dfr(
        2:5,
        ~ estimate_one_cell(group_value, .x)
      )
    }
  )
  
  term_label_table <- make_term_label_table(env)
  
  subgroup_coefficients <- subgroup_coefficients %>%
    dplyr::left_join(term_label_table, by = "term") %>%
    dplyr::mutate(
      attribute = dplyr::coalesce(attribute, "その他"),
      label = dplyr::coalesce(label, term),
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      party_n_label = factor(
        party_n,
        levels = 2:5,
        labels = paste0(2:5, ifelse(study_id == "study3", "選択肢", "政党"))
      )
    )
  
  readr::write_csv(
    subgroup_coefficients,
    file.path(out_dir, "party_support_subgroup_amce_coefficients.csv"),
    na = ""
  )
  
  for (group_value in eligible_groups) {
    plot_dat <- subgroup_coefficients %>%
      dplyr::filter(
        party_support_h == group_value,
        status == "estimated",
        !is.na(term)
      )
    
    if (nrow(plot_dat) == 0) next
    
    label_order <- plot_dat %>%
      dplyr::arrange(attribute, dplyr::coalesce(order, 9999), label) %>%
      dplyr::distinct(label) %>%
      dplyr::pull(label)
    
    plot_dat <- plot_dat %>%
      dplyr::mutate(
        label = factor(label, levels = rev(label_order))
      )
    
    n_group <- support_totals %>%
      dplyr::filter(party_support_h == group_value) %>%
      dplyr::pull(n_total_distinct)
    
    p_group <- ggplot2::ggplot(
      plot_dat,
      ggplot2::aes(
        x = estimate_pp,
        y = label,
        shape = party_n_label
      )
    ) +
      ggplot2::geom_vline(xintercept = 0, linewidth = 0.45) +
      ggplot2::geom_errorbarh(
        ggplot2::aes(
          xmin = conf.low_pp,
          xmax = conf.high_pp
        ),
        height = 0.10,
        position = ggplot2::position_dodge(width = 0.55),
        linewidth = 0.55
      ) +
      ggplot2::geom_point(
        position = ggplot2::position_dodge(width = 0.55),
        size = 2.3,
        fill = "white"
      ) +
      ggplot2::facet_grid(
        attribute ~ .,
        scales = "free_y",
        space = "free_y"
      ) +
      ggplot2::labs(
        x = "選択確率への効果(percentage points)",
        y = NULL,
        shape = study_spec$condition_label,
        subtitle = paste0(
          study_label,
          ":",
          group_value,
          "支持者(n = ",
          scales::comma(n_group),
          ")"
        ),
        caption = paste0(
          "回答者IDでクラスタ化した標準誤差。各条件セルn < ",
          unified_config$min_support_cell_n,
          "は推定しない。"
        )
      ) +
      ggplot2::theme_bw(base_size = 10.5) +
      ggplot2::theme(
        panel.grid.minor = ggplot2::element_blank(),
        strip.background = ggplot2::element_rect(fill = "white"),
        strip.text = ggplot2::element_text(face = "bold"),
        legend.position = "bottom",
        axis.text = ggplot2::element_text(color = "black")
      )
    
    group_index <- match(group_value, eligible_groups)
    file_stub <- paste0(
      study_id,
      "_party_support_amce_",
      sprintf("%02d", group_index),
      "_",
      safe_filename(group_value)
    )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, paste0(file_stub, ".png")),
      plot = p_group,
      width = 10.5,
      height = ifelse(study_id == "study3", 11.5, 10.0),
      dpi = 400,
      bg = "white"
    )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, paste0(file_stub, ".pdf")),
      plot = p_group,
      width = 10.5,
      height = ifelse(study_id == "study3", 11.5, 10.0),
      device = grDevices::cairo_pdf,
      bg = "white"
    )
  }
  
  interaction_models <- list()
  interaction_test_text <- character()
  
  dat_interaction <- dat %>%
    dplyr::filter(party_support_h %in% eligible_groups) %>%
    dplyr::mutate(
      party_support_h = factor(party_support_h)
    )
  
  if ("支持政党なし" %in% levels(dat_interaction$party_support_h)) {
    dat_interaction <- dat_interaction %>%
      dplyr::mutate(
        party_support_h = stats::relevel(
          party_support_h,
          ref = "支持政党なし"
        )
      )
  } else if (nrow(support_totals) > 0) {
    largest_group <- support_totals %>%
      dplyr::filter(party_support_h %in% eligible_groups) %>%
      dplyr::slice_max(n_total_distinct, n = 1, with_ties = FALSE) %>%
      dplyr::pull(party_support_h)
    
    if (length(largest_group) == 1) {
      dat_interaction <- dat_interaction %>%
        dplyr::mutate(
          party_support_h = stats::relevel(
            party_support_h,
            ref = largest_group
          )
        )
    }
  }
  
  formula_interaction <- stats::as.formula(
    paste0(
      "selected ~ party_support_h * (",
      paste(env$attr_terms, collapse = " + "),
      ")"
    )
  )
  
  for (n_value in 2:5) {
    dat_n <- dat_interaction %>% dplyr::filter(party_n == n_value)
    
    model_n <- tryCatch(
      fixest::feols(
        formula_interaction,
        data = dat_n,
        vcov = ~ ID
      ),
      error = function(e) e
    )
    
    interaction_models[[as.character(n_value)]] <- model_n
    
    interaction_test_text <- c(
      interaction_test_text,
      paste0("\n===== ", study_label, ": condition ", n_value, " =====\n")
    )
    
    if (inherits(model_n, "error")) {
      interaction_test_text <- c(
        interaction_test_text,
        paste0("Model error: ", conditionMessage(model_n), "\n")
      )
    } else {
      interaction_test_text <- c(
        interaction_test_text,
        capture.output(summary(model_n)),
        "\n--- Joint Wald test for party-support interaction terms ---\n",
        tryCatch(
          capture.output(
            fixest::wald(
              model_n,
              keep = "party_support_h.*:|:party_support_h"
            )
          ),
          error = function(e) paste0("Wald test error: ", conditionMessage(e))
        )
      )
    }
  }
  
  writeLines(
    interaction_test_text,
    con = file.path(out_dir, "party_support_interaction_models_and_wald_tests.txt")
  )
  
  list(
    support_counts = support_counts,
    eligible_groups = eligible_groups,
    subgroup_coefficients = subgroup_coefficients,
    interaction_models = interaction_models,
    data = dat
  )
}

party_support_amce_results <- purrr::map(
  study_specs,
  run_support_amce_heterogeneity
)

run_support_relative_cue <- function(study_spec, amce_result) {
  env <- study_spec$env
  study_id <- study_spec$study_id
  out_dir <- file.path(unified_output_dir, paste0(study_id, "_party_support"))
  
  dat <- amce_result$data
  eligible_groups <- amce_result$eligible_groups
  
  observed_list <- list()
  interval_list <- list()
  slope_list <- list()
  failure_list <- list()
  
  for (group_index in seq_along(eligible_groups)) {
    group_value <- eligible_groups[group_index]
    dat_group <- dat %>%
      dplyr::filter(party_support_h == group_value)
    
    condition_counts <- dat_group %>%
      dplyr::distinct(ID, party_n) %>%
      dplyr::count(party_n, name = "n_ids")
    
    if (
      !identical(sort(condition_counts$party_n), 2:5) ||
      any(condition_counts$n_ids < unified_config$min_support_cell_n)
    ) {
      failure_list[[group_value]] <- tibble::tibble(
        party_support_h = group_value,
        reason = "Not all four conditions meet the minimum cell size"
      )
      next
    }
    
    prepared <- tryCatch(
      env$prepare_relative_cue_analysis(
        data = dat_group,
        cue_map = env$relative_cue_map
      ),
      error = function(e) e
    )
    
    if (inherits(prepared, "error")) {
      failure_list[[group_value]] <- tibble::tibble(
        party_support_h = group_value,
        reason = conditionMessage(prepared)
      )
      next
    }
    
    observed <- env$estimate_relative_cue_indices(prepared)
    observed_slopes <- env$estimate_relative_cue_slopes(
      observed$cue_importance
    )
    
    observed_list[[group_value]] <- observed$cue_importance %>%
      dplyr::mutate(
        party_support_h = group_value,
        .before = 1
      )
    
    slope_list[[group_value]] <- tibble::tibble(
      party_support_h = group_value,
      statistic = names(observed_slopes),
      estimate = as.numeric(observed_slopes)
    )
    
    B <- unified_config$support_bootstrap_B
    
    if (B > 0) {
      cache_file <- file.path(
        out_dir,
        paste0(
          "support_relative_cue_bootstrap_",
          unified_config$cue_importance_metric_version,
          "_",
          sprintf("%02d", group_index),
          "_B",
          B,
          ".rds"
        )
      )
      
      if (
        file.exists(cache_file) &&
        !unified_config$rerun_support_bootstrap
      ) {
        bootstrap_result <- readRDS(cache_file)
      } else {
        bootstrap_result <- env$run_relative_cue_bootstrap(
          prepared = prepared,
          B = B,
          seed = unified_config$support_bootstrap_seed +
            1000 * match(study_id, names(study_specs)) +
            group_index,
          progress_every = max(0, floor(B / 5))
        )
        saveRDS(bootstrap_result, cache_file)
      }
      
      intervals <- env$summarise_condition_intervals(
        observed_cue_importance = observed$cue_importance,
        bootstrap_condition_results = bootstrap_result$condition_estimates
      ) %>%
        dplyr::mutate(
          party_support_h = group_value,
          .before = 1
        )
      
      slope_inference <- env$summarise_slope_inference(
        observed_slopes = observed_slopes,
        bootstrap_slopes = bootstrap_result$slopes
      ) %>%
        dplyr::mutate(
          party_support_h = group_value,
          .before = 1
        )
      
      interval_list[[group_value]] <- intervals
      slope_list[[paste0(group_value, "_inference")]] <- slope_inference
    }
  }
  
  observed_df <- dplyr::bind_rows(observed_list)
  interval_df <- dplyr::bind_rows(interval_list)
  slope_df <- dplyr::bind_rows(slope_list)
  failures_df <- dplyr::bind_rows(failure_list)
  
  readr::write_csv(
    observed_df,
    file.path(out_dir, "party_support_relative_cue_observed.csv"),
    na = ""
  )
  readr::write_csv(
    interval_df,
    file.path(out_dir, "party_support_relative_cue_intervals.csv"),
    na = ""
  )
  readr::write_csv(
    slope_df,
    file.path(out_dir, "party_support_relative_cue_slopes.csv"),
    na = ""
  )
  readr::write_csv(
    failures_df,
    file.path(out_dir, "party_support_relative_cue_failures.csv"),
    na = ""
  )
  
  if (nrow(interval_df) > 0) {
    plot_df <- interval_df %>%
      dplyr::filter(statistic == "relative_party_weight_pairwise") %>%
      dplyr::mutate(
        estimate_pct = estimate * 100,
        conf_low_pct = conf_low * 100,
        conf_high_pct = conf_high * 100
      )
  } else {
    plot_df <- observed_df %>%
      dplyr::transmute(
        party_support_h,
        party_n,
        estimate_pct = relative_party_weight_pairwise * 100,
        conf_low_pct = NA_real_,
        conf_high_pct = NA_real_
      )
  }
  
  if (nrow(plot_df) > 0) {
    p_relative_support <- ggplot2::ggplot(
      plot_df,
      ggplot2::aes(
        x = party_n,
        y = estimate_pct,
        group = 1
      )
    ) +
      ggplot2::geom_hline(yintercept = 50, linetype = "dashed", linewidth = 0.45) +
      ggplot2::geom_line(linewidth = 0.70) +
      ggplot2::geom_errorbar(
        ggplot2::aes(
          ymin = conf_low_pct,
          ymax = conf_high_pct
        ),
        width = 0.08,
        linewidth = 0.55,
        na.rm = TRUE
      ) +
      ggplot2::geom_point(shape = 21, fill = "white", size = 2.5) +
      ggplot2::facet_wrap(~ party_support_h, ncol = 3) +
      ggplot2::scale_x_continuous(
        breaks = 2:5,
        labels = paste0(2:5, ifelse(study_id == "study3", "選択肢", "政党"))
      ) +
      ggplot2::scale_y_continuous(
        labels = function(x) paste0(x, "%"),
        breaks = scales::pretty_breaks(n = 6)
      ) +
      ggplot2::labs(
        x = study_spec$condition_label,
        y = "政党手がかりの相対比重",
        subtitle = paste0(
          study_spec$study_label,
          ":支持政党別の政党手がかり相対比重"
        ),
        caption = paste0(
          "各属性内の限界平均の平均絶対ペア差に基づく。",
          ifelse(
            unified_config$support_bootstrap_B > 0,
            paste0(
              "95%信頼区間は回答者クラスタ・ブートストラップ(B = ",
              unified_config$support_bootstrap_B,
              ")。"
            ),
            "信頼区間は未計算。"
          )
        )
      ) +
      ggplot2::theme_bw(base_size = 10.5) +
      ggplot2::theme(
        panel.grid.minor = ggplot2::element_blank(),
        strip.background = ggplot2::element_rect(fill = "white"),
        strip.text = ggplot2::element_text(face = "bold"),
        axis.text = ggplot2::element_text(color = "black")
      )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, "party_support_relative_cue_weight.png"),
      plot = p_relative_support,
      width = 11.5,
      height = max(7.0, 2.6 * ceiling(dplyr::n_distinct(plot_df$party_support_h) / 3)),
      dpi = 400,
      bg = "white"
    )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, "party_support_relative_cue_weight.pdf"),
      plot = p_relative_support,
      width = 11.5,
      height = max(7.0, 2.6 * ceiling(dplyr::n_distinct(plot_df$party_support_h) / 3)),
      device = grDevices::cairo_pdf,
      bg = "white"
    )
  } else {
    p_relative_support <- NULL
  }
  
  list(
    observed = observed_df,
    intervals = interval_df,
    slopes = slope_df,
    failures = failures_df,
    plot = p_relative_support
  )
}

party_support_relative_cue_results <- purrr::map2(
  study_specs,
  party_support_amce_results,
  run_support_relative_cue
)


# 補遺I関連コード
extract_cue_slope_inference <- function(study_spec) {
  env <- study_spec$env
  
  env$relative_cue_slope_inference %>%
    dplyr::mutate(
      study_id = study_spec$study_id,
      study_label = study_spec$study_label,
      .before = 1
    )
}

cue_slope_inference_all <- purrr::map_dfr(
  study_specs,
  extract_cue_slope_inference
) %>%
  dplyr::mutate(
    statistic_label = dplyr::recode(
      statistic,
      party_importance_pairwise = "政党の手がかりの未調整重要度",
      economic_importance_pairwise = "経済の手がかりの未調整重要度",
      party_importance_pairwise_adjusted =
        "政党の手がかりの選択肢数調整済み重要度",
      economic_importance_pairwise_adjusted =
        "経済の手がかりの選択肢数調整済み重要度",
      relative_party_weight_pairwise = "政党の手がかりの相対比重"
    ),
    metric_scale = dplyr::case_when(
      statistic %in% c(
        "party_importance_pairwise_adjusted",
        "economic_importance_pairwise_adjusted"
      ) ~ "choice_set_adjusted_baseline_relative",
      statistic == "relative_party_weight_pairwise" ~
        "relative_share",
      TRUE ~ "unadjusted_probability_difference"
    ),
    estimate_pp_per_option = estimate * 100,
    conf_low_pp_per_option = conf_low * 100,
    conf_high_pp_per_option = conf_high * 100
  )

write_csv_unified(
  cue_slope_inference_all,
  "cue_importance_linear_slope_all_studies.csv"
)

choice_set_adjusted_slope_summary <- cue_slope_inference_all %>%
  dplyr::filter(
    statistic %in% c(
      "party_importance_pairwise_adjusted",
      "economic_importance_pairwise_adjusted"
    )
  ) %>%
  dplyr::mutate(
    cue_family = dplyr::recode(
      statistic,
      party_importance_pairwise_adjusted =
        "政党・政党名手がかり",
      economic_importance_pairwise_adjusted =
        "経済手がかり"
    ),
    estimate_baseline_pct_per_option = estimate * 100,
    conf_low_baseline_pct_per_option = conf_low * 100,
    conf_high_baseline_pct_per_option = conf_high * 100
  )

write_csv_unified(
  choice_set_adjusted_slope_summary,
  "choice_set_adjusted_importance_linear_slopes.csv"
)

hypothesis_map <- tibble::tribble(
  ~study_id, ~hypothesis, ~statistic, ~expected_direction,
  "study1", "H1a(実験1)", "party_importance_pairwise", "positive",
  "study1", "H1b(実験1)", "economic_importance_pairwise", "negative",
  "study2", "H1a(実験2)", "party_importance_pairwise", "positive",
  "study2", "H1b(実験2)", "economic_importance_pairwise", "negative",
  "study3", "H2a(実験3)", "party_importance_pairwise", "positive",
  "study3", "H2b(実験3)", "economic_importance_pairwise", "negative"
)

hypothesis_test_summary <- hypothesis_map %>%
  dplyr::left_join(
    cue_slope_inference_all %>%
      dplyr::select(
        study_id,
        study_label,
        statistic,
        estimate,
        conf_low,
        conf_high,
        p_value_two_sided
      ),
    by = c("study_id", "statistic")
  ) %>%
  dplyr::mutate(
    estimate_in_expected_direction = dplyr::case_when(
      expected_direction == "positive" ~ estimate > 0,
      expected_direction == "negative" ~ estimate < 0,
      TRUE ~ NA
    ),
    ci_excludes_zero_in_expected_direction = dplyr::case_when(
      expected_direction == "positive" ~ conf_low > 0,
      expected_direction == "negative" ~ conf_high < 0,
      TRUE ~ NA
    ),
    conclusion = dplyr::case_when(
      ci_excludes_zero_in_expected_direction ~
        "予測方向で95%信頼区間が0を含まず、統計的に支持",
      estimate_in_expected_direction ~
        "点推定は予測方向だが、95%信頼区間が0を含む",
      TRUE ~
        "点推定が予測方向と一致しない"
    ),
    estimate_pp_per_option = estimate * 100,
    conf_low_pp_per_option = conf_low * 100,
    conf_high_pp_per_option = conf_high * 100,
    hypothesis = factor(
      hypothesis,
      levels = rev(hypothesis_map$hypothesis)
    )
  )

write_csv_unified(
  hypothesis_test_summary,
  "main_hypothesis_linear_trend_tests.csv"
)

p_hypothesis_slopes <- ggplot2::ggplot(
  hypothesis_test_summary,
  ggplot2::aes(
    x = estimate_pp_per_option,
    y = hypothesis,
    shape = expected_direction
  )
) +
  ggplot2::geom_vline(
    xintercept = 0,
    linewidth = 0.45
  ) +
  ggplot2::geom_errorbarh(
    ggplot2::aes(
      xmin = conf_low_pp_per_option,
      xmax = conf_high_pp_per_option
    ),
    height = 0.12,
    linewidth = 0.60
  ) +
  ggplot2::geom_point(
    size = 2.7,
    fill = "white"
  ) +
  ggplot2::scale_shape_manual(
    values = c(
      positive = 21,
      negative = 24
    ),
    labels = c(
      positive = "正の傾向を予測",
      negative = "負の傾向を予測"
    )
  ) +
  ggplot2::labs(
    x = "選択肢が1つ増えるときの重要度の変化(pp)",
    y = NULL,
    shape = NULL,
    caption = paste0(
      "重要度は、同一属性内の全水準ペアについて限界平均の絶対差を求め、",
      "その平均として算出。横線は回答者クラスタ・ブートストラップ95%信頼区間。"
    )
  ) +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(
    panel.grid.minor = ggplot2::element_blank(),
    legend.position = "bottom",
    axis.text = ggplot2::element_text(color = "black")
  )

save_plot_both(
  "fig_supp_hypothesis_linear_trend_tests",
  p_hypothesis_slopes,
  width = 9.5,
  height = 5.8
)

choice_set_adjusted_slope_summary <- choice_set_adjusted_slope_summary %>%
  dplyr::mutate(
    study_cue_label = paste0(
      study_label,
      ":",
      cue_family
    ),
    study_cue_label = factor(
      study_cue_label,
      levels = rev(
        unique(study_cue_label)
      )
    )
  )

p_choice_set_adjusted_slopes <- ggplot2::ggplot(
  choice_set_adjusted_slope_summary,
  ggplot2::aes(
    x = estimate_baseline_pct_per_option,
    y = study_cue_label,
    shape = cue_family
  )
) +
  ggplot2::geom_vline(
    xintercept = 0,
    linewidth = 0.45
  ) +
  ggplot2::geom_errorbarh(
    ggplot2::aes(
      xmin = conf_low_baseline_pct_per_option,
      xmax = conf_high_baseline_pct_per_option
    ),
    height = 0.12,
    linewidth = 0.60
  ) +
  ggplot2::geom_point(
    size = 2.7,
    fill = "white"
  ) +
  ggplot2::scale_shape_manual(
    values = c(
      "政党・政党名手がかり" = 21,
      "経済手がかり" = 24
    )
  ) +
  ggplot2::labs(
    x = paste0(
      "選択肢が1つ増えるときの調整済み重要度の変化",
      "(平均選択確率に対する割合:pp)"
    ),
    y = NULL,
    shape = NULL,
    caption = paste0(
      "調整済み重要度 = 未調整重要度 ÷(1/選択肢数)。",
      "事前登録済み仮説の判定ではなく、記述的・感度分析として示す。"
    )
  ) +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(
    panel.grid.minor = ggplot2::element_blank(),
    legend.position = "bottom",
    axis.text = ggplot2::element_text(color = "black")
  )

save_plot_both(
  "fig_supp_choice_set_adjusted_importance_slopes",
  p_choice_set_adjusted_slopes,
  width = 10.5,
  height = 6.2
)


# 本文コード
run_study3_all_party_match <- function() {
  env <- study3_env
  out_dir <- file.path(unified_output_dir, "study3_party_match_all_parties")
  dir.create(out_dir, showWarnings = FALSE, recursive = TRUE)
  
  dat <- env$conjoint_match %>%
    dplyr::mutate(
      ID = as.character(ID),
      party_n = as.integer(as.character(party_n)),
      support_party_valid = as.character(support_party_valid)
    ) %>%
    dplyr::filter(
      !is.na(support_party_valid),
      support_party_valid != ""
    )
  
  support_cell_counts <- dat %>%
    dplyr::distinct(ID, support_party_valid, party_n) %>%
    dplyr::count(
      support_party_valid,
      party_n,
      name = "n_respondents"
    ) %>%
    tidyr::complete(
      support_party_valid,
      party_n = 2:5,
      fill = list(n_respondents = 0L)
    ) %>%
    dplyr::group_by(support_party_valid) %>%
    dplyr::mutate(
      n_total = sum(n_respondents),
      min_cell_n = min(n_respondents),
      all_four_conditions = all(n_respondents > 0)
    ) %>%
    dplyr::ungroup()
  
  eligible_parties <- support_cell_counts %>%
    dplyr::distinct(
      support_party_valid,
      n_total,
      min_cell_n,
      all_four_conditions
    ) %>%
    dplyr::filter(
      n_total >= unified_config$min_support_total_n,
      min_cell_n >= unified_config$min_support_cell_n,
      all_four_conditions
    ) %>%
    dplyr::arrange(dplyr::desc(n_total)) %>%
    dplyr::pull(support_party_valid)
  
  readr::write_csv(
    support_cell_counts,
    file.path(out_dir, "party_match_all_party_sample_counts.csv"),
    na = ""
  )
  
  formula_cell <- stats::as.formula(
    paste(
      "selected ~",
      paste(
        c(
          "party_match",
          env$economic_attr_terms
        ),
        collapse = " + "
      )
    )
  )
  
  estimate_cell <- function(group_value, n_value) {
    dat_cell <- dat %>%
      dplyr::filter(
        support_party_valid == group_value,
        party_n == n_value
      )
    
    n_ids <- dplyr::n_distinct(dat_cell$ID)
    
    if (n_ids < unified_config$min_support_cell_n) {
      return(
        tibble::tibble(
          support_party_valid = group_value,
          party_n = n_value,
          n_ids = n_ids,
          estimate = NA_real_,
          std.error = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_,
          p.value = NA_real_,
          status = "insufficient_cell_n"
        )
      )
    }
    
    model <- tryCatch(
      fixest::feols(
        formula_cell,
        data = dat_cell,
        vcov = ~ ID
      ),
      error = function(e) e
    )
    
    if (inherits(model, "error")) {
      return(
        tibble::tibble(
          support_party_valid = group_value,
          party_n = n_value,
          n_ids = n_ids,
          estimate = NA_real_,
          std.error = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_,
          p.value = NA_real_,
          status = paste0("model_error: ", conditionMessage(model))
        )
      )
    }
    
    tidy_fixest_unified(model) %>%
      dplyr::filter(term == "party_match") %>%
      dplyr::transmute(
        support_party_valid = group_value,
        party_n = n_value,
        n_ids = n_ids,
        estimate,
        std.error,
        conf.low,
        conf.high,
        p.value,
        status = "estimated"
      )
  }
  
  cell_coefficients <- purrr::map_dfr(
    eligible_parties,
    function(group_value) {
      purrr::map_dfr(
        2:5,
        ~ estimate_cell(group_value, .x)
      )
    }
  ) %>%
    dplyr::mutate(
      estimate_pp = estimate * 100,
      conf.low_pp = conf.low * 100,
      conf.high_pp = conf.high * 100,
      party_n_label = factor(
        party_n,
        levels = 2:5,
        labels = paste0(2:5, "選択肢")
      ),
      main_text_party = support_party_valid %in% c(
        "自由民主党",
        "中道改革連合",
        "立憲民主党",
        "参政党"
      )
    )
  
  readr::write_csv(
    cell_coefficients,
    file.path(out_dir, "party_match_all_party_coefficients.csv"),
    na = ""
  )
  
  estimate_trend <- function(group_value) {
    dat_group <- dat %>%
      dplyr::filter(support_party_valid == group_value) %>%
      dplyr::mutate(
        party_n_f_heterogeneity = factor(
          party_n,
          levels = 2:5
        ),
        party_n_c_heterogeneity = party_n - 2
      )
    
    formula_trend <- stats::as.formula(
      paste(
        "selected ~ party_n_f_heterogeneity + party_match +",
        "party_match:party_n_c_heterogeneity +",
        paste(env$economic_attr_terms, collapse = " + ")
      )
    )
    
    model <- tryCatch(
      fixest::feols(
        formula_trend,
        data = dat_group,
        vcov = ~ ID
      ),
      error = function(e) e
    )
    
    if (inherits(model, "error")) {
      return(
        tibble::tibble(
          support_party_valid = group_value,
          term = "party_match:party_n_c_heterogeneity",
          estimate = NA_real_,
          std.error = NA_real_,
          conf.low = NA_real_,
          conf.high = NA_real_,
          p.value = NA_real_,
          status = paste0("model_error: ", conditionMessage(model))
        )
      )
    }
    
    tidy_fixest_unified(model) %>%
      dplyr::filter(
        stringr::str_detect(
          term,
          "party_match:party_n_c_heterogeneity|party_n_c_heterogeneity:party_match"
        )
      ) %>%
      dplyr::mutate(
        support_party_valid = group_value,
        status = "estimated",
        .before = 1
      )
  }
  
  trend_coefficients <- purrr::map_dfr(
    eligible_parties,
    estimate_trend
  ) %>%
    dplyr::mutate(
      estimate_pp_per_option = estimate * 100,
      conf.low_pp_per_option = conf.low * 100,
      conf.high_pp_per_option = conf.high * 100
    )
  
  readr::write_csv(
    trend_coefficients,
    file.path(out_dir, "party_match_all_party_linear_trends.csv"),
    na = ""
  )
  
  plot_df <- cell_coefficients %>%
    dplyr::filter(
      status == "estimated",
      is.finite(estimate_pp)
    ) %>%
    dplyr::mutate(
      support_party_valid = factor(
        support_party_valid,
        levels = eligible_parties
      )
    )
  
  if (nrow(plot_df) > 0) {
    p_all_party_match <- ggplot2::ggplot(
      plot_df,
      ggplot2::aes(
        x = party_n,
        y = estimate_pp,
        group = 1
      )
    ) +
      ggplot2::geom_hline(
        yintercept = 0,
        linewidth = 0.40
      ) +
      ggplot2::geom_line(
        linewidth = 0.65
      ) +
      ggplot2::geom_errorbar(
        ggplot2::aes(
          ymin = conf.low_pp,
          ymax = conf.high_pp
        ),
        width = 0.08,
        linewidth = 0.55
      ) +
      ggplot2::geom_point(
        shape = 21,
        fill = "white",
        size = 2.4
      ) +
      ggplot2::facet_wrap(
        ~ support_party_valid,
        ncol = 3
      ) +
      ggplot2::scale_x_continuous(
        breaks = 2:5,
        labels = paste0(2:5, "選択肢")
      ) +
      ggplot2::labs(
        x = "提示される選択肢数",
        y = "支持政党と提示政党名の一致効果(pp)",
        caption = paste0(
          "各支持政党サブグループ内で selected ~ party_match + 経済属性を推定。",
          "標準誤差は回答者IDでクラスタ化。"
        )
      ) +
      ggplot2::theme_bw(base_size = 10.5) +
      ggplot2::theme(
        panel.grid.minor = ggplot2::element_blank(),
        strip.background = ggplot2::element_rect(fill = "white"),
        strip.text = ggplot2::element_text(face = "bold"),
        axis.text = ggplot2::element_text(color = "black")
      )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, "party_match_all_parties.png"),
      plot = p_all_party_match,
      width = 11.5,
      height = max(
        7.0,
        2.7 * ceiling(length(eligible_parties) / 3)
      ),
      dpi = 400,
      bg = "white"
    )
    
    ggplot2::ggsave(
      filename = file.path(out_dir, "party_match_all_parties.pdf"),
      plot = p_all_party_match,
      width = 11.5,
      height = max(
        7.0,
        2.7 * ceiling(length(eligible_parties) / 3)
      ),
      device = grDevices::cairo_pdf,
      bg = "white"
    )
  } else {
    p_all_party_match <- NULL
  }
  
  list(
    sample_counts = support_cell_counts,
    eligible_parties = eligible_parties,
    coefficients = cell_coefficients,
    trends = trend_coefficients,
    plot = p_all_party_match
  )
}

study3_all_party_match_results <- run_study3_all_party_match()


extract_cross_study_relative_weight <- function(study_spec) {
  env <- study_spec$env
  
  env$relative_cue_condition_intervals %>%
    dplyr::filter(
      statistic == "relative_party_weight_pairwise"
    ) %>%
    dplyr::transmute(
      study_id = study_spec$study_id,
      study_label = study_spec$study_label,
      party_n,
      estimate,
      conf_low,
      conf_high
    )
}

cross_study_relative_weight <- purrr::map_dfr(
  study_specs,
  extract_cross_study_relative_weight
) %>%
  dplyr::mutate(
    estimate_pct = estimate * 100,
    conf_low_pct = conf_low * 100,
    conf_high_pct = conf_high * 100,
    study_label = factor(
      study_label,
      levels = vapply(
        study_specs,
        `[[`,
        character(1),
        "study_label"
      )
    )
  )

write_csv_unified(
  cross_study_relative_weight,
  "cross_study_relative_party_weight.csv"
)

p_cross_study_relative <- ggplot2::ggplot(
  cross_study_relative_weight,
  ggplot2::aes(
    x = party_n,
    y = estimate_pct,
    linetype = study_label,
    shape = study_label,
    group = study_label
  )
) +
  ggplot2::geom_hline(
    yintercept = 50,
    linetype = "dotted",
    linewidth = 0.45
  ) +
  ggplot2::geom_line(
    linewidth = 0.80
  ) +
  ggplot2::geom_errorbar(
    ggplot2::aes(
      ymin = conf_low_pct,
      ymax = conf_high_pct
    ),
    width = 0.07,
    linewidth = 0.60,
    position = ggplot2::position_dodge(width = 0.08)
  ) +
  ggplot2::geom_point(
    size = 2.7,
    fill = "white",
    position = ggplot2::position_dodge(width = 0.08)
  ) +
  ggplot2::scale_x_continuous(
    breaks = 2:5,
    labels = paste0(2:5, "選択肢")
  ) +
  ggplot2::scale_y_continuous(
    labels = function(x) paste0(x, "%"),
    breaks = scales::pretty_breaks(n = 6)
  ) +
  ggplot2::labs(
    x = "提示される選択肢数",
    y = "政党の手がかりの相対比重",
    linetype = NULL,
    shape = NULL,
    caption = paste0(
      "限界平均の平均絶対ペア差に基づく。",
      "エラーバーは回答者クラスタ・ブートストラップ95%信頼区間。"
    )
  ) +
  ggplot2::theme_bw(base_size = 11.5) +
  ggplot2::theme(
    panel.grid.minor = ggplot2::element_blank(),
    legend.position = "bottom",
    axis.text = ggplot2::element_text(color = "black")
  )

save_plot_both(
  "fig_supp_cross_study_relative_party_weight",
  p_cross_study_relative,
  width = 9.5,
  height = 6.0
)


# 出力整理コード
main_text_figure_manifest <- tibble::tribble(
  ~figure_number, ~study, ~analysis, ~file_png, ~file_pdf,
  "Figure 4", "Study 1", "共変量調整済みAMCE",
  file.path(unified_config$study1$output_dir, "amce_cov_facet_model.png"),
  NA_character_,
  "Figure 5", "Study 1", "政党・経済手がかりの重要度と相対比重",
  file.path(unified_config$study1$output_dir, "fig_study1_relative_cue_weight_jp_bw.png"),
  file.path(unified_config$study1$output_dir, "fig_study1_relative_cue_weight_jp_bw.pdf"),
  "Figure 6", "Study 2", "共変量調整済みAMCE",
  file.path(unified_config$study2$output_dir, "amce_cov_facet_model.png"),
  NA_character_,
  "Figure 7", "Study 2", "政党・経済手がかりの重要度と相対比重",
  file.path(unified_config$study2$output_dir, "fig_study2_relative_cue_weight_jp_bw.png"),
  file.path(unified_config$study2$output_dir, "fig_study2_relative_cue_weight_jp_bw.pdf"),
  "Figure 8", "Study 3", "共変量調整済みAMCE",
  file.path(unified_config$study3$output_dir, "amce_cov_facet_model.png"),
  NA_character_,
  "Figure 9", "Study 3", "政党名・経済手がかりの重要度と相対比重",
  file.path(unified_config$study3$output_dir, "fig_study3_relative_cue_weight_jp_bw.png"),
  file.path(unified_config$study3$output_dir, "fig_study3_relative_cue_weight_jp_bw.pdf"),
  "Figure 10", "Study 3", "支持政党と提示政党名の一致効果",
  file.path(unified_config$study3$output_dir, "party_match_effect_combined.png"),
  NA_character_
)

write_csv_unified(
  main_text_figure_manifest,
  "main_text_figure_reproduction_manifest.csv"
)

supplement_figure_manifest <- tibble::tribble(
  ~section, ~study, ~analysis, ~file_png,
  "B", "Study 1", "回答者割付バランス:Love plot",
  file.path(unified_output_dir, "study1_assignment_balance_love_plot.png"),
  "B", "Study 2", "回答者割付バランス:Love plot",
  file.path(unified_output_dir, "study2_assignment_balance_love_plot.png"),
  "B", "Study 3", "回答者割付バランス:Love plot",
  file.path(unified_output_dir, "study3_assignment_balance_love_plot.png"),
  "B", "Study 1", "回答者割付バランス:45度線診断",
  file.path(unified_output_dir, "study1_assignment_balance_diagonal_plot.png"),
  "B", "Study 2", "回答者割付バランス:45度線診断",
  file.path(unified_output_dir, "study2_assignment_balance_diagonal_plot.png"),
  "B", "Study 3", "回答者割付バランス:45度線診断",
  file.path(unified_output_dir, "study3_assignment_balance_diagonal_plot.png"),
  "B", "Study 1", "属性水準の観測比率対期待比率",
  file.path(unified_output_dir, "study1_profile_randomization_diagonal_plot.png"),
  "B", "Study 2", "属性水準の観測比率対期待比率",
  file.path(unified_output_dir, "study2_profile_randomization_diagonal_plot.png"),
  "B", "Study 3", "属性水準の観測比率対期待比率",
  file.path(unified_output_dir, "study3_profile_randomization_diagonal_plot.png"),
  "C", "Study 1–3", "H1a/H1b/H2a/H2bの線形傾向検定",
  file.path(unified_output_dir, "fig_supp_hypothesis_linear_trend_tests.png"),
  "C", "Study 1–3", "選択肢数調整済み重要度の線形傾向",
  file.path(unified_output_dir, "fig_supp_choice_set_adjusted_importance_slopes.png"),
  "C", "Study 1", "未調整・選択肢数調整済み重要度・相対比重",
  file.path(
    unified_config$study1$output_dir,
    "fig_study1_relative_cue_weight_choice_set_adjusted_jp_bw.png"
  ),
  "C", "Study 2", "未調整・選択肢数調整済み重要度・相対比重",
  file.path(
    unified_config$study2$output_dir,
    "fig_study2_relative_cue_weight_choice_set_adjusted_jp_bw.png"
  ),
  "C", "Study 3", "未調整・選択肢数調整済み重要度・相対比重",
  file.path(
    unified_config$study3$output_dir,
    "fig_study3_relative_cue_weight_choice_set_adjusted_jp_bw.png"
  ),
  "F", "Study 1–3", "政党手がかり相対比重の横断比較",
  file.path(unified_output_dir, "fig_supp_cross_study_relative_party_weight.png"),
  "G", "Study 3", "全ての十分な標本をもつ支持政党の一致効果",
  file.path(
    unified_output_dir,
    "study3_party_match_all_parties",
    "party_match_all_parties.png"
  ),
  "G", "Study 1–3", "支持政党別AMCE・相対比重",
  file.path(unified_output_dir, "<study>_party_support")
)

write_csv_unified(
  supplement_figure_manifest,
  "supplement_figure_manifest.csv"
)

supplement_section_manifest <- tibble::tribble(
  ~section, ~title, ~placement_logic, ~core_outputs,
  "A", "調査設計・質問文・標本構築",
  "読者が3実験の相違と分析対象者の形成を先に確認できるようにする。",
  "調査フロー、属性・水準、質問文、sample_flow、条件別n、欠損集計",
  "B", "無作為割付・属性提示・データ品質の診断",
  "推定結果より前に、処置条件とコンジョイント属性の無作為化が機能したことを示す。",
  "条件別共変量表、全6条件ペアのSMD、Love plot、45度線図、属性水準の観測対期待比率",
  "C", "推定量・相対比重・仮説検定",
  "本文の式(1)(2)とH1a/H1b/H2a/H2bの判定方法を一か所に集約する。",
  paste0(
    "AMCE、限界平均、平均絶対ペア差、選択肢数調整済み重要度、",
    "相対比重、ブートストラップ、線形傾向統合表"
  ),
  "D", "実験1(2023年)の完全な結果",
  "本文図4・5の再現後に、補助分析を同じ実験内でまとめる。",
  "調整済み・未調整AMCE、交互作用、ヒートマップ、条件付きロジット、相対比重傾向",
  "E", "実験2(2026年)と2023–2026年比較",
  "実験1の再現性と時点間変化を連続して読めるようにする。",
  "調整済み・未調整AMCE、交互作用、ヒートマップ、条件付きロジット、相対比重傾向、時点比較",
  "F", "実験3(2026年)の完全な結果",
  "具体的政党名の分析と、本文図8・9・10の追加推定をまとめる。",
  "AMCE、カテゴリカル・線形トレンド、条件付きロジット、相対比重、一致効果",
  "G", "政党支持による異質性",
  "本文の党派性メカニズムに直結するため、頑健性分析から独立させる。",
  "支持政党別AMCE、支持政党×属性Wald検定、支持政党別相対比重、全政党一致効果",
  "H", "除外基準・推定法・標本定義に関する感度分析",
  "主要結論が分析上の選択に依存しないかを最後に確認する。",
  "注意・操作確認、完全5課題、共変量なし、条件付きロジット、代替標本",
  "I", "再現性情報",
  "全ての分析後に、再現に必要な技術情報をまとめる。",
  "ファイル一覧、乱数シード、ブートストラップ回数、パッケージ、sessionInfo"
)

write_csv_unified(
  supplement_section_manifest,
  "supplement_section_manifest.csv"
)

saveRDS(
  list(
    config = unified_config,
    assignment_balance = assignment_balance_results,
    profile_randomization = profile_randomization_results,
    cue_slope_inference = cue_slope_inference_all,
    choice_set_adjusted_slope_summary =
      choice_set_adjusted_slope_summary,
    choice_set_adjusted_slope_plot =
      p_choice_set_adjusted_slopes,
    hypothesis_tests = hypothesis_test_summary,
    party_support_amce = party_support_amce_results,
    party_support_relative_cue = party_support_relative_cue_results,
    study3_all_party_match = study3_all_party_match_results,
    cross_study_relative_weight = cross_study_relative_weight,
    cross_study_relative_plot = p_cross_study_relative,
    main_text_figure_manifest = main_text_figure_manifest,
    supplement_figure_manifest = supplement_figure_manifest,
    supplement_section_manifest = supplement_section_manifest
  ),
  file = file.path(
    unified_output_dir,
    "unified_supplement_objects.rds"
  )
)

capture.output(
  sessionInfo(),
  file = file.path(
    unified_output_dir,
    "sessionInfo_unified.txt"
  )
)

cat(
  "\n3実験の本文図再現・補遺分析・支持政党別異質性分析が完了しました。\n",
  "統合出力先: ",
  normalizePath(unified_output_dir),
  "\n",
  sep = ""
)


final_output_root <- unified_config$output_root

final_dirs <- list(
  main_figures = file.path(final_output_root, "main_text", "figures"),
  main_tables = file.path(final_output_root, "main_text", "tables"),
  supplement_root = file.path(final_output_root, "supplement"),
  supplement_cross = file.path(final_output_root, "supplement", "cross_study"),
  diagnostics_root = file.path(final_output_root, "diagnostics"),
  model_objects_root = file.path(final_output_root, "model_objects"),
  logs = file.path(final_output_root, "logs")
)

invisible(
  lapply(
    final_dirs,
    dir.create,
    showWarnings = FALSE,
    recursive = TRUE
  )
)

for (study_id in names(study_specs)) {
  for (subdir in c("figures", "tables_csv", "tables_tex")) {
    dir.create(
      file.path(final_dirs$supplement_root, study_id, subdir),
      showWarnings = FALSE,
      recursive = TRUE
    )
  }
  for (subdir in c("screening", "balance", "randomization")) {
    dir.create(
      file.path(final_dirs$diagnostics_root, study_id, subdir),
      showWarnings = FALSE,
      recursive = TRUE
    )
  }
  dir.create(
    file.path(final_dirs$model_objects_root, study_id),
    showWarnings = FALSE,
    recursive = TRUE
  )
}

for (subdir in c("figures", "tables_csv", "tables_tex")) {
  dir.create(
    file.path(final_dirs$supplement_cross, subdir),
    showWarnings = FALSE,
    recursive = TRUE
  )
}


copy_file_if_exists <- function(source, destination) {
  if (is.na(source) || !nzchar(source) || !file.exists(source)) {
    return(FALSE)
  }
  dir.create(dirname(destination), showWarnings = FALSE, recursive = TRUE)
  isTRUE(file.copy(source, destination, overwrite = TRUE, copy.mode = TRUE))
}

copy_files_by_pattern <- function(source_dir, destination_dir, pattern) {
  if (!dir.exists(source_dir)) {
    return(character())
  }
  files <- list.files(
    source_dir,
    pattern = pattern,
    full.names = TRUE,
    recursive = TRUE,
    ignore.case = TRUE
  )
  if (length(files) == 0) {
    return(character())
  }
  dir.create(destination_dir, showWarnings = FALSE, recursive = TRUE)
  destinations <- file.path(destination_dir, basename(files))
  copied <- vapply(
    seq_along(files),
    function(i) copy_file_if_exists(files[i], destinations[i]),
    logical(1)
  )
  destinations[copied]
}

latex_escape <- function(x) {
  x <- as.character(x)
  x[is.na(x)] <- ""

  escape_one <- function(s) {
    chars <- strsplit(s, "", fixed = TRUE)[[1]]

    if (length(chars) == 0L) {
      return("")
    }

    replacement <- c(
      "\\" = "\\textbackslash{}",
      "&"  = "\\&",
      "%"  = "\\%",
      "$"  = "\\$",
      "#"  = "\\#",
      "_"  = "\\_",
      "{"  = "\\{",
      "}"  = "\\}",
      "~"  = "\\textasciitilde{}",
      "^"  = "\\textasciicircum{}"
    )

    out <- vapply(
      chars,
      function(ch) {
        if (ch %in% names(replacement)) {
          unname(replacement[[ch]])
        } else {
          ch
        }
      },
      character(1)
    )

    paste0(out, collapse = "")
  }

  vapply(x, escape_one, character(1), USE.NAMES = FALSE)
}

format_number <- function(x, digits = 3) {
  out <- ifelse(
    is.na(x),
    "",
    formatC(x, format = "f", digits = digits)
  )
  as.character(out)
}

format_integer <- function(x) {
  ifelse(is.na(x), "", scales::comma(as.integer(round(x))))
}

format_p_value <- function(x) {
  dplyr::case_when(
    is.na(x) ~ "",
    x < 0.001 ~ "< .001",
    TRUE ~ sub("^0", "", formatC(x, format = "f", digits = 3))
  )
}

write_latex_longtable <- function(
    data,
    file,
    caption,
    label,
    notes = NULL,
    landscape = ncol(data) >= 7) {
  
  data <- as.data.frame(data, stringsAsFactors = FALSE)
  if (ncol(data) == 0) {
    data <- data.frame(note = "該当する推定結果はありません。")
  }
  
  display <- data
  display[] <- lapply(display, function(x) latex_escape(as.character(x)))
  headers <- latex_escape(names(display))
  
  numeric_column <- vapply(data, is.numeric, logical(1))
  alignment <- paste0(ifelse(numeric_column, "r", "l"), collapse = "")
  
  lines <- character()
  lines <- c(lines, "% Generated automatically by the replication script.")
  if (landscape) {
    lines <- c(lines, "\\begin{landscape}")
  }
  lines <- c(
    lines,
    "\\begingroup",
    "\\small",
    paste0("\\begin{longtable}{", alignment, "}"),
    paste0("\\caption{", latex_escape(caption), "}\\label{", label, "}\\\\"),
    "\\toprule",
    paste(headers, collapse = " & "),
    "\\\\",
    "\\midrule",
    "\\endfirsthead",
    paste0("\\multicolumn{", ncol(display), "}{l}{\\tablename~\\thetable{}(続き)}\\\\"),
    "\\toprule",
    paste(headers, collapse = " & "),
    "\\\\",
    "\\midrule",
    "\\endhead",
    paste0("\\midrule\\multicolumn{", ncol(display), "}{r}{次頁に続く}\\\\"),
    "\\endfoot",
    "\\bottomrule",
    "\\endlastfoot"
  )
  
  if (nrow(display) > 0) {
    row_lines <- apply(
      display,
      1,
      function(row) paste0(paste(row, collapse = " & "), " \\\\")
    )
    lines <- c(lines, row_lines)
  }
  
  lines <- c(lines, "\\end{longtable}")
  if (!is.null(notes) && nzchar(notes)) {
    lines <- c(
      lines,
      "\\vspace{-0.5em}",
      "\\begin{minipage}{\\linewidth}",
      "\\footnotesize",
      paste0("\\textit{注:}", latex_escape(notes)),
      "\\end{minipage}"
    )
  }
  lines <- c(lines, "\\endgroup")
  if (landscape) {
    lines <- c(lines, "\\end{landscape}")
  }
  
  dir.create(dirname(file), showWarnings = FALSE, recursive = TRUE)
  writeLines(lines, con = file, useBytes = TRUE)
  invisible(file)
}

write_csv_and_tex <- function(
    data,
    csv_file,
    tex_file,
    caption,
    label,
    notes = NULL,
    landscape = ncol(data) >= 7) {
  dir.create(dirname(csv_file), showWarnings = FALSE, recursive = TRUE)
  readr::write_csv(data, csv_file, na = "")
  write_latex_longtable(
    data = data,
    file = tex_file,
    caption = caption,
    label = label,
    notes = notes,
    landscape = landscape
  )
  invisible(list(csv = csv_file, tex = tex_file))
}

attribute_label_map <- c(
  policy_position = "政策位置",
  government_status = "与野党地位",
  seats = "議席数",
  party_name = "政党名",
  gdp_growth = "GDP成長率",
  nikkei = "日経平均株価",
  cpi = "消費者物価指数(CPI)",
  unemployment = "失業率"
)

cue_family_label <- c(
  party = "政党の手がかり",
  economic = "経済の手がかり"
)


screening_specs <- list(
  study1 = list(
    initial_consent_var = "Q1.1",
    final_consent_var = study1_env$final_consent_var,
    attention_var = NA_character_,
    attention_answer = NA_character_,
    manipulation_available = FALSE,
    intro_map = NULL
  ),
  study2 = list(
    initial_consent_var = "Q1.1",
    final_consent_var = study2_env$final_consent_var,
    attention_var = study2_env$attention_check_var,
    attention_answer = as.character(study2_env$attention_check_correct),
    manipulation_available = TRUE,
    intro_map = NULL
  ),
  study3 = list(
    initial_consent_var = "Q1.1",
    final_consent_var = study3_env$final_consent_var,
    attention_var = study3_env$attention_check_var,
    attention_answer = as.character(study3_env$attention_check_correct),
    manipulation_available = TRUE,
    intro_map = NULL
  )
)

response_present <- function(x) {
  x <- as.character(x)
  !is.na(x) & stringr::str_squish(x) != ""
}

response_is_code <- function(x, code) {
  x <- stringr::str_squish(as.character(x))
  code <- as.character(code)
  out <- x == code | stringr::str_detect(x, paste0("\\(", code, "\\)$"))
  out[is.na(out)] <- FALSE
  out
}

get_mapped_response <- function(data, assigned_n, map, value_column) {
  result <- rep(NA_character_, nrow(data))
  for (n_value in 2:5) {
    row <- map[map$party_n == n_value, , drop = FALSE]
    if (nrow(row) == 0) next
    variable <- as.character(row[[value_column]][1])
    if (!variable %in% names(data)) next
    take <- !is.na(assigned_n) & assigned_n == n_value
    result[take] <- as.character(data[[variable]][take])
  }
  result
}

infer_assigned_condition <- function(data, choice_map, manipulation_map = NULL, intro_map = NULL) {
  candidate <- matrix(FALSE, nrow = nrow(data), ncol = 4)
  colnames(candidate) <- as.character(2:5)
  
  for (n_value in 2:5) {
    variables <- choice_map$choice_var[choice_map$party_n == n_value]
    if (!is.null(manipulation_map) && nrow(manipulation_map) > 0) {
      variables <- c(
        variables,
        manipulation_map$manipulation_var[manipulation_map$party_n == n_value]
      )
    }
    if (!is.null(intro_map) && as.character(n_value) %in% names(intro_map)) {
      variables <- c(variables, unname(intro_map[as.character(n_value)]))
    }
    variables <- intersect(unique(variables), names(data))
    if (length(variables) > 0) {
      candidate[, as.character(n_value)] <- apply(
        data[, variables, drop = FALSE],
        1,
        function(row) any(response_present(row))
      )
    }
  }
  
  n_candidates <- rowSums(candidate)
  assigned <- rep(NA_integer_, nrow(data))
  single <- n_candidates == 1
  assigned[single] <- as.integer(colnames(candidate)[max.col(candidate[single, , drop = FALSE])])
  
  if (any(n_candidates > 1)) {
    warning("Check")
  }
  assigned
}

build_screening_outputs <- function(study_spec) {
  study_id <- study_spec$study_id
  env <- study_spec$env
  spec <- screening_specs[[study_id]]
  raw <- env$df_header_removed %>%
    dplyr::mutate(ID = as.character(ID)) %>%
    dplyr::distinct(ID, .keep_all = TRUE)
  
  manipulation_map <- if (
    spec$manipulation_available &&
    exists("manipulation_map", envir = env, inherits = FALSE)
  ) {
    get("manipulation_map", envir = env, inherits = FALSE)
  } else {
    NULL
  }
  
  assigned_n <- infer_assigned_condition(
    data = raw,
    choice_map = env$choice_map,
    manipulation_map = manipulation_map,
    intro_map = spec$intro_map
  )
  
  if (exists("id_task_check", envir = env, inherits = FALSE)) {
    analysis_assignment <- get("id_task_check", envir = env, inherits = FALSE) %>%
      dplyr::mutate(
        ID = as.character(ID),
        party_n = as.integer(as.character(party_n))
      ) %>%
      dplyr::group_by(ID) %>%
      dplyr::summarise(
        n_condition_candidates = dplyr::n_distinct(party_n),
        assigned_from_analysis = dplyr::if_else(
          n_condition_candidates == 1L,
          dplyr::first(party_n),
          NA_integer_
        ),
        .groups = "drop"
      )
    
    analysis_match <- match(raw$ID, analysis_assignment$ID)
    use_analysis_assignment <- !is.na(analysis_match) &
      !is.na(analysis_assignment$assigned_from_analysis[analysis_match])
    assigned_n[use_analysis_assignment] <-
      analysis_assignment$assigned_from_analysis[analysis_match[use_analysis_assignment]]
  }
  
  if (exists("valid_ids", envir = env, inherits = FALSE)) {
    final_assignment <- get("valid_ids", envir = env, inherits = FALSE) %>%
      dplyr::mutate(
        ID = as.character(ID),
        party_n = as.integer(as.character(party_n))
      ) %>%
      dplyr::distinct(ID, party_n) %>%
      dplyr::group_by(ID) %>%
      dplyr::summarise(
        n_condition_candidates = dplyr::n_distinct(party_n),
        assigned_from_final = dplyr::if_else(
          n_condition_candidates == 1L,
          dplyr::first(party_n),
          NA_integer_
        ),
        .groups = "drop"
      )
    
    final_match <- match(raw$ID, final_assignment$ID)
    use_final_assignment <- !is.na(final_match) &
      !is.na(final_assignment$assigned_from_final[final_match])
    assigned_n[use_final_assignment] <-
      final_assignment$assigned_from_final[final_match[use_final_assignment]]
  }
  
  initial_response <- if (spec$initial_consent_var %in% names(raw)) {
    raw[[spec$initial_consent_var]]
  } else {
    rep(NA_character_, nrow(raw))
  }
  final_response <- if (spec$final_consent_var %in% names(raw)) {
    raw[[spec$final_consent_var]]
  } else {
    rep(NA_character_, nrow(raw))
  }
  
  task_responses <- lapply(
    1:5,
    function(task_value) {
      task_map <- env$choice_map[env$choice_map$task == task_value, , drop = FALSE]
      get_mapped_response(raw, assigned_n, task_map, "choice_var")
    }
  )
  
  task_pass <- lapply(
    task_responses,
    function(response) {
      parsed <- suppressWarnings(readr::parse_number(as.character(response)))
      !is.na(assigned_n) & !is.na(parsed) & parsed >= 1 & parsed <= assigned_n
    }
  )
  
  if (!is.null(manipulation_map)) {
    manipulation_response <- get_mapped_response(
      raw,
      assigned_n,
      manipulation_map,
      "manipulation_var"
    )
    manipulation_answer <- rep(NA_character_, nrow(raw))
    for (n_value in 2:5) {
      answer <- manipulation_map$correct_answer[manipulation_map$party_n == n_value]
      manipulation_answer[!is.na(assigned_n) & assigned_n == n_value] <- answer[1]
    }
    manipulation_pass <- !is.na(assigned_n) & response_is_code(
      manipulation_response,
      manipulation_answer
    )
  } else {
    manipulation_response <- rep(NA_character_, nrow(raw))
    manipulation_pass <- rep(TRUE, nrow(raw))
  }
  
  if (!is.na(spec$attention_var) && spec$attention_var %in% names(raw)) {
    attention_response <- raw[[spec$attention_var]]
    attention_pass <- response_is_code(attention_response, spec$attention_answer)
  } else {
    attention_response <- rep(NA_character_, nrow(raw))
    attention_pass <- rep(TRUE, nrow(raw))
  }
  
  initial_pass <- response_is_code(initial_response, 1) |
    stringr::str_detect(
      stringr::str_squish(as.character(initial_response)),
      "趣旨に同意して.*協力する"
    )
  final_pass <- response_is_code(final_response, 1) |
    stringr::str_detect(
      stringr::str_squish(as.character(final_response)),
      "同意し.*回答結果を送信する"
    )
  
  final_ids <- as.character(env$valid_ids$ID)
  
  audit <- tibble::tibble(
    ID = raw$ID,
    assigned_condition = assigned_n,
    initial_consent_response = as.character(initial_response),
    initial_consent_pass = initial_pass,
    reached_conjoint_block = !is.na(assigned_n),
    task1_response = as.character(task_responses[[1]]),
    task1_complete = task_pass[[1]],
    task2_response = as.character(task_responses[[2]]),
    task2_complete = task_pass[[2]],
    task3_response = as.character(task_responses[[3]]),
    task3_complete = task_pass[[3]],
    task4_response = as.character(task_responses[[4]]),
    task4_complete = task_pass[[4]],
    task5_response = as.character(task_responses[[5]]),
    task5_complete = task_pass[[5]],
    all_five_tasks_complete = Reduce(`&`, task_pass),
    manipulation_response = as.character(manipulation_response),
    manipulation_check_pass = manipulation_pass,
    attention_response = as.character(attention_response),
    attention_check_pass = attention_pass,
    final_consent_response = as.character(final_response),
    final_consent_pass = final_pass,
    included_in_final_analysis = ID %in% final_ids
  )
  
  cumulative <- rep(TRUE, nrow(audit))
  stage_records <- list()
  add_stage <- function(stage, question_variable, criterion) {
    cumulative <<- cumulative & criterion
    stage_records[[length(stage_records) + 1L]] <<- tibble::tibble(
      stage_order = length(stage_records) + 1L,
      stage = stage,
      question_variable = question_variable,
      n_remaining = sum(cumulative, na.rm = TRUE)
    )
  }
  
  add_stage("Qualtricsの質問文・ImportId行を除外", "ResponseId", rep(TRUE, nrow(audit)))
  add_stage("初回同意", spec$initial_consent_var, audit$initial_consent_pass)
  add_stage("割付されたコンジョイント・ブロックに到達", "Q3.1/Q4.1/Q5.1/Q6.1 または最初の選択課題", audit$reached_conjoint_block)
  for (task_value in 1:5) {
    add_stage(
      paste0("選択課題", task_value, "を有効回答"),
      paste0("条件別 choice task ", task_value),
      audit[[paste0("task", task_value, "_complete")]]
    )
  }
  if (spec$manipulation_available) {
    add_stage(
      "提示された選択肢数を正答",
      "条件別に自動検出した選択肢数確認質問",
      audit$manipulation_check_pass
    )
  }
  if (!is.na(spec$attention_var)) {
    add_stage(
      "イデオロギー行列の指示項目に正答",
      spec$attention_var,
      audit$attention_check_pass
    )
  }
  add_stage("最終送信同意", spec$final_consent_var, audit$final_consent_pass)
  add_stage("最終分析標本", "全基準の積集合", audit$included_in_final_analysis)
  
  flow <- dplyr::bind_rows(stage_records) %>%
    dplyr::mutate(
      n_excluded_at_stage = dplyr::lag(n_remaining, default = dplyr::first(n_remaining)) - n_remaining,
      retention_from_previous_pct = dplyr::if_else(
        dplyr::lag(n_remaining, default = dplyr::first(n_remaining)) > 0,
        100 * n_remaining / dplyr::lag(n_remaining, default = dplyr::first(n_remaining)),
        NA_real_
      ),
      retention_from_initial_pct = 100 * n_remaining / dplyr::first(n_remaining)
    )
  
  condition_flow <- purrr::map_dfr(
    2:5,
    function(n_value) {
      subset_audit <- audit %>% dplyr::filter(assigned_condition == n_value)
      if (nrow(subset_audit) == 0) {
        return(tibble::tibble())
      }
      criteria <- list(
        "割付条件を識別" = rep(TRUE, nrow(subset_audit)),
        "選択課題1" = subset_audit$task1_complete,
        "選択課題2" = subset_audit$task2_complete,
        "選択課題3" = subset_audit$task3_complete,
        "選択課題4" = subset_audit$task4_complete,
        "選択課題5" = subset_audit$task5_complete
      )
      if (spec$manipulation_available) {
        criteria[["選択肢数確認"]] <- subset_audit$manipulation_check_pass
      }
      if (!is.na(spec$attention_var)) {
        criteria[["指示項目"]] <- subset_audit$attention_check_pass
      }
      criteria[["最終送信同意"]] <- subset_audit$final_consent_pass
      criteria[["最終分析標本"]] <- subset_audit$included_in_final_analysis
      
      keep <- rep(TRUE, nrow(subset_audit))
      records <- purrr::imap_dfr(
        criteria,
        function(criterion, stage_name) {
          keep <<- keep & criterion
          tibble::tibble(
            assigned_condition = n_value,
            stage_order = which(names(criteria) == stage_name),
            stage = stage_name,
            n_remaining = sum(keep, na.rm = TRUE)
          )
        }
      )
      records %>%
        dplyr::mutate(
          n_excluded_at_stage = dplyr::lag(n_remaining, default = dplyr::first(n_remaining)) - n_remaining,
          retention_from_condition_start_pct = 100 * n_remaining / dplyr::first(n_remaining)
        )
    }
  )
  
  final_audit <- audit %>% dplyr::filter(included_in_final_analysis)
  required_final <- final_audit$initial_consent_pass &
    final_audit$all_five_tasks_complete &
    final_audit$manipulation_check_pass &
    final_audit$attention_check_pass &
    final_audit$final_consent_pass
  if (!all(required_final)) {
    stop("Check")
  }
  if (nrow(final_audit) != dplyr::n_distinct(env$valid_ids$ID)) {
    stop("Check")
  }
  
  list(audit = audit, flow = flow, condition_flow = condition_flow)
}


make_amce_table <- function(env, adjusted = TRUE) {
  source <- if (adjusted) env$amce_plot_cov else env$amce_plot_nocov
  n_table <- env$n_by_party %>%
    dplyr::transmute(
      party_n_numeric = as.integer(as.character(party_n)),
      respondents = n
    )
  
  source %>%
    dplyr::mutate(
      party_n_numeric = suppressWarnings(readr::parse_number(as.character(party_n)))
    ) %>%
    dplyr::left_join(n_table, by = "party_n_numeric") %>%
    dplyr::transmute(
      `条件` = as.character(party_n),
      `属性` = as.character(attribute),
      `水準(基準水準との差)` = as.character(label),
      `推定値(pp)` = format_number(100 * estimate, 2),
      `標準誤差(pp)` = format_number(100 * std.error, 2),
      `95% CI下限(pp)` = format_number(100 * conf.low, 2),
      `95% CI上限(pp)` = format_number(100 * conf.high, 2),
      `p値` = format_p_value(p.value),
      `回答者数` = format_integer(respondents)
    )
}

make_interaction_table <- function(env) {
  source <- env$interaction_plot_df
  condition_column <- intersect(c("party_n_label", "party_n"), names(source))[1]
  if (is.na(condition_column)) {
    source$condition_label <- ""
  } else {
    source$condition_label <- as.character(source[[condition_column]])
  }
  source %>%
    dplyr::transmute(
      `比較条件` = condition_label,
      `属性` = as.character(attribute),
      `水準` = as.character(label),
      `2選択肢条件との差(pp)` = format_number(100 * estimate, 2),
      `標準誤差(pp)` = format_number(100 * std.error, 2),
      `95% CI下限(pp)` = format_number(100 * conf.low, 2),
      `95% CI上限(pp)` = format_number(100 * conf.high, 2),
      `p値` = format_p_value(p.value)
    )
}

clustered_mean_summary <- function(y, cluster) {
  y <- as.numeric(y)
  cluster <- as.character(cluster)
  keep <- is.finite(y) & !is.na(cluster)
  y <- y[keep]
  cluster <- cluster[keep]
  n <- length(y)
  g <- dplyr::n_distinct(cluster)
  if (n == 0) {
    return(c(estimate = NA_real_, se = NA_real_, low = NA_real_, high = NA_real_, n = 0, g = 0))
  }
  estimate <- mean(y)
  if (g <= 1) {
    se <- NA_real_
  } else {
    cluster_score <- tapply(y - estimate, cluster, sum)
    variance <- (g / (g - 1)) * sum(cluster_score^2) / (n^2)
    se <- sqrt(variance)
  }
  c(
    estimate = estimate,
    se = se,
    low = estimate - 1.96 * se,
    high = estimate + 1.96 * se,
    n = n,
    g = g
  )
}

make_mm_table <- function(env) {
  attributes <- names(env$relative_cue_map)
  long <- env$conjoint_all_m %>%
    dplyr::select(ID, party_n, selected, dplyr::all_of(attributes)) %>%
    tidyr::pivot_longer(
      cols = dplyr::all_of(attributes),
      names_to = "attribute",
      values_to = "level"
    ) %>%
    dplyr::filter(!is.na(level), as.character(level) != "") %>%
    dplyr::mutate(level = as.character(level))
  
  summary <- long %>%
    dplyr::group_by(party_n, attribute, level) %>%
    dplyr::group_modify(
      ~ {
        values <- clustered_mean_summary(.x$selected, .x$ID)
        tibble::tibble(
          marginal_mean = values["estimate"],
          cluster_se = values["se"],
          conf_low = values["low"],
          conf_high = values["high"],
          n_profiles = values["n"],
          n_respondents = values["g"]
        )
      }
    ) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(
      cue_family = unname(env$relative_cue_map[attribute]),
      attribute_label = dplyr::coalesce(unname(attribute_label_map[attribute]), attribute),
      cue_label = dplyr::coalesce(unname(cue_family_label[cue_family]), cue_family)
    )
  
  summary %>%
    dplyr::transmute(
      `条件` = paste0(party_n, ifelse("party_name" %in% attributes, "選択肢", "政党")),
      `手がかり群` = cue_label,
      `属性` = attribute_label,
      `水準` = level,
      `限界平均(%)` = format_number(100 * marginal_mean, 2),
      `クラスタSE(pp)` = format_number(100 * cluster_se, 2),
      `95% CI下限(%)` = format_number(100 * conf_low, 2),
      `95% CI上限(%)` = format_number(100 * conf_high, 2),
      `プロファイル数` = format_integer(n_profiles),
      `回答者数` = format_integer(n_respondents)
    )
}

make_attribute_importance_table <- function(env) {
  source <- env$relative_cue_observed$attribute_importance
  adjusted_col <- intersect(
    c("importance_pairwise_adjusted", "choice_set_adjusted_importance_pairwise"),
    names(source)
  )[1]
  adjusted <- if (!is.na(adjusted_col)) source[[adjusted_col]] else source$party_n * source$importance_pairwise
  
  source %>%
    dplyr::mutate(
      adjusted_value = adjusted,
      attribute_label = dplyr::coalesce(unname(attribute_label_map[attribute]), attribute),
      cue_label = dplyr::coalesce(unname(cue_family_label[cue_family]), cue_family)
    ) %>%
    dplyr::transmute(
      `条件` = party_n,
      `手がかり群` = cue_label,
      `属性` = attribute_label,
      `水準数` = n_levels,
      `未調整重要度(pp)` = format_number(100 * importance_pairwise, 2),
      `選択肢数調整済み重要度(%)` = format_number(100 * adjusted_value, 2)
    )
}

make_cue_importance_table <- function(env) {
  source <- env$relative_cue_condition_intervals
  labels <- c(
    party_importance_pairwise = "政党手がかり:未調整重要度",
    economic_importance_pairwise = "経済手がかり:未調整重要度",
    party_importance_pairwise_adjusted = "政党手がかり:選択肢数調整済み重要度",
    economic_importance_pairwise_adjusted = "経済手がかり:選択肢数調整済み重要度",
    relative_party_weight_pairwise = "政党手がかりの相対比重"
  )
  source <- source %>% dplyr::filter(statistic %in% names(labels))
  source %>%
    dplyr::mutate(
      `指標` = unname(labels[statistic]),
      `単位` = dplyr::case_when(
        statistic %in% c("party_importance_pairwise", "economic_importance_pairwise") ~ "pp",
        TRUE ~ "%"
      ),
      multiplier = 100
    ) %>%
    dplyr::transmute(
      `条件` = party_n,
      `指標` = `指標`,
      `単位` = `単位`,
      `推定値` = format_number(multiplier * estimate, 2),
      `95% CI下限` = format_number(multiplier * conf_low, 2),
      `95% CI上限` = format_number(multiplier * conf_high, 2)
    )
}

make_clogit_table <- function(env) {
  env$clogit_plot_df %>%
    dplyr::transmute(
      `条件` = as.character(party_n),
      `属性` = as.character(attribute),
      `水準(基準水準との差)` = as.character(label),
      `log係数` = format_number(estimate, 3),
      `標準誤差` = format_number(std.error, 3),
      `オッズ比` = format_number(odds_ratio, 3),
      `95% CI下限(OR)` = format_number(odds_ratio_low, 3),
      `95% CI上限(OR)` = format_number(odds_ratio_high, 3),
      `p値` = format_p_value(p.value)
    )
}

make_linear_trend_table <- function(env) {
  if (!exists("linear_trend_plot_df", envir = env, inherits = FALSE)) {
    return(tibble::tibble())
  }
  env$linear_trend_plot_df %>%
    dplyr::transmute(
      `属性` = as.character(attribute),
      `水準` = as.character(label),
      `選択肢が1つ増えるときの変化(pp)` = format_number(100 * estimate, 2),
      `標準誤差(pp)` = format_number(100 * std.error, 2),
      `95% CI下限(pp)` = format_number(100 * conf.low, 2),
      `95% CI上限(pp)` = format_number(100 * conf.high, 2),
      `p値` = format_p_value(p.value)
    )
}

make_party_match_table <- function(env) {
  if (!exists("party_match_coef_df", envir = env, inherits = FALSE)) {
    return(tibble::tibble())
  }
  overall <- env$party_match_coef_df
  subgroup <- if (exists("party_match_subgroup_coef_df", envir = env, inherits = FALSE)) {
    env$party_match_subgroup_coef_df
  } else {
    tibble::tibble()
  }
  combined <- dplyr::bind_rows(overall, subgroup)
  if (!"n_ids" %in% names(combined)) combined$n_ids <- NA_real_
  if (!"support_group_label" %in% names(combined)) combined$support_group_label <- "全体"
  combined %>%
    dplyr::mutate(
      support_group_label = dplyr::coalesce(as.character(support_group_label), "全体"),
      n_ids = suppressWarnings(as.numeric(n_ids))
    ) %>%
    dplyr::transmute(
      `対象` = support_group_label,
      `選択肢数` = party_n,
      `一致効果(pp)` = format_number(100 * estimate, 2),
      `標準誤差(pp)` = format_number(100 * std.error, 2),
      `95% CI下限(pp)` = format_number(100 * conf.low, 2),
      `95% CI上限(pp)` = format_number(100 * conf.high, 2),
      `p値` = format_p_value(p.value),
      `回答者数` = format_integer(n_ids)
    )
}


screening_results <- list()
study_table_paths <- list()

for (study_id in names(study_specs)) {
  spec <- study_specs[[study_id]]
  env <- spec$env
  study_label <- spec$study_label
  csv_dir <- file.path(final_dirs$supplement_root, study_id, "tables_csv")
  tex_dir <- file.path(final_dirs$supplement_root, study_id, "tables_tex")
  diag_screen_dir <- file.path(final_dirs$diagnostics_root, study_id, "screening")
  diag_balance_dir <- file.path(final_dirs$diagnostics_root, study_id, "balance")
  diag_random_dir <- file.path(final_dirs$diagnostics_root, study_id, "randomization")
  
  screening <- build_screening_outputs(spec)
  screening_results[[study_id]] <- screening
  
  readr::write_csv(screening$audit, file.path(diag_screen_dir, "respondent_screening_audit.csv"), na = "")
  readr::write_csv(screening$flow, file.path(diag_screen_dir, "sequential_sample_flow.csv"), na = "")
  readr::write_csv(screening$condition_flow, file.path(diag_screen_dir, "sequential_sample_flow_by_condition.csv"), na = "")
  
  attrition_table <- screening$flow %>%
    dplyr::transmute(
      `順序` = stage_order,
      `段階` = stage,
      `質問・変数` = question_variable,
      `残存N` = format_integer(n_remaining),
      `当該段階での除外N` = format_integer(n_excluded_at_stage),
      `前段階からの残存率(%)` = format_number(retention_from_previous_pct, 1),
      `初期標本からの残存率(%)` = format_number(retention_from_initial_pct, 1)
    )
  
  write_csv_and_tex(
    attrition_table,
    file.path(csv_dir, "table_sample_attrition.csv"),
    file.path(tex_dir, "table_sample_attrition.tex"),
    paste0(study_label, ":質問段階ごとの逐次的な標本減少"),
    paste0("tab:", study_id, "-attrition"),
    notes = paste0(
      "各行は直前までの基準を満たした回答者に次の基準を順に適用した残存数を示す。",
      ifelse(
        study_id == "study1",
        "Study 1では選択肢数確認質問および指示項目は調査票に設けられていない。",
        "最終分析は、選択肢数確認とQ25.1_11の指示項目の双方に正答した回答者に限定した。"
      )
    )
  )
  
  condition_attrition_table <- screening$condition_flow %>%
    dplyr::transmute(
      `条件` = assigned_condition,
      `順序` = stage_order,
      `段階` = stage,
      `残存N` = format_integer(n_remaining),
      `当該段階での除外N` = format_integer(n_excluded_at_stage),
      `条件開始時からの残存率(%)` = format_number(retention_from_condition_start_pct, 1)
    )
  write_csv_and_tex(
    condition_attrition_table,
    file.path(csv_dir, "table_sample_attrition_by_condition.csv"),
    file.path(tex_dir, "table_sample_attrition_by_condition.tex"),
    paste0(study_label, ":条件別の逐次的な標本減少"),
    paste0("tab:", study_id, "-attrition-condition"),
    notes = "条件を回答履歴から識別できた回答者について、各条件内で基準を累積的に適用した。"
  )
  
  manipulation_table <- screening$audit %>%
    dplyr::filter(!is.na(assigned_condition)) %>%
    dplyr::count(
      assigned_condition,
      manipulation_response,
      manipulation_check_pass,
      name = "n"
    ) %>%
    dplyr::transmute(
      `条件` = assigned_condition,
      `回答` = dplyr::coalesce(manipulation_response, "未実施・欠損"),
      `正答` = ifelse(manipulation_check_pass, "正答", "不正答・欠損"),
      `N` = format_integer(n)
    )
  if (study_id == "study1") {
    manipulation_table <- tibble::tibble(
      `条件` = "全条件",
      `回答` = "調査票に選択肢数確認質問なし",
      `正答` = "適用外",
      `N` = ""
    )
  }
  write_csv_and_tex(
    manipulation_table,
    file.path(csv_dir, "table_manipulation_check.csv"),
    file.path(tex_dir, "table_manipulation_check.tex"),
    paste0(study_label, ":選択肢数の操作確認"),
    paste0("tab:", study_id, "-manipulation-check"),
    notes = "Study 2・3では、割り当てられた選択肢数と同じ回答を正答とした。"
  )
  
  attention_table <- screening$audit %>%
    dplyr::count(attention_response, attention_check_pass, name = "n") %>%
    dplyr::transmute(
      `回答` = dplyr::coalesce(attention_response, "未実施・欠損"),
      `判定` = ifelse(attention_check_pass, "正答", "不正答・欠損"),
      `N` = format_integer(n)
    )
  if (study_id == "study1") {
    attention_table <- tibble::tibble(
      `回答` = "調査票に指示項目なし",
      `判定` = "適用外",
      `N` = ""
    )
  }
  write_csv_and_tex(
    attention_table,
    file.path(csv_dir, "table_attention_check.csv"),
    file.path(tex_dir, "table_attention_check.tex"),
    paste0(study_label, ":イデオロギー行列の指示項目"),
    paste0("tab:", study_id, "-attention-check"),
    notes = "Study 2・3では、調査画面上の指示項目で「3」を選択した回答者を正答とした。Qualtricsの保存コードが表示値と異なる場合は、本分析で自動検出された保存コードを用いた。"
  )
  
  amce_cov <- make_amce_table(env, adjusted = TRUE)
  amce_nocov <- make_amce_table(env, adjusted = FALSE)
  interaction <- make_interaction_table(env)
  mm_table <- make_mm_table(env)
  attr_importance <- make_attribute_importance_table(env)
  cue_importance <- make_cue_importance_table(env)
  clogit_table <- make_clogit_table(env)
  linear_trend_table <- make_linear_trend_table(env)
  party_match_table <- make_party_match_table(env)
  
  write_csv_and_tex(
    amce_cov,
    file.path(csv_dir, "table_amce_covariate_adjusted.csv"),
    file.path(tex_dir, "table_amce_covariate_adjusted.tex"),
    paste0(study_label, ":共変量調整済みAMCE"),
    paste0("tab:", study_id, "-amce-adjusted"),
    notes = "推定値の単位はパーセントポイント。標準誤差は回答者単位でクラスタ化した。"
  )
  write_csv_and_tex(
    amce_nocov,
    file.path(csv_dir, "table_amce_unadjusted.csv"),
    file.path(tex_dir, "table_amce_unadjusted.tex"),
    paste0(study_label, ":共変量を含めないAMCE"),
    paste0("tab:", study_id, "-amce-unadjusted"),
    notes = "推定値の単位はパーセントポイント。標準誤差は回答者単位でクラスタ化した。"
  )
  write_csv_and_tex(
    interaction,
    file.path(csv_dir, "table_amce_interaction.csv"),
    file.path(tex_dir, "table_amce_interaction.tex"),
    paste0(study_label, ":2選択肢条件との差を表すAMCE交互作用"),
    paste0("tab:", study_id, "-amce-interaction"),
    notes = "正の値は、当該条件におけるAMCEが2選択肢条件より大きいことを示す。"
  )
  write_csv_and_tex(
    mm_table,
    file.path(csv_dir, "table_marginal_means.csv"),
    file.path(tex_dir, "table_marginal_means.tex"),
    paste0(study_label, ":属性水準別の限界平均(MM)"),
    paste0("tab:", study_id, "-marginal-means"),
    notes = "限界平均は当該水準をもつプロファイルの平均選択確率。SEと信頼区間は回答者クラスタに対応した切片のみの線形確率モデルと同値の計算による。"
  )
  write_csv_and_tex(
    attr_importance,
    file.path(csv_dir, "table_attribute_importance.csv"),
    file.path(tex_dir, "table_attribute_importance.tex"),
    paste0(study_label, ":属性別の未調整・選択肢数調整済み重要度"),
    paste0("tab:", study_id, "-attribute-importance"),
    notes = "未調整重要度は限界平均の全水準ペアの絶対差の平均。調整済み重要度は未調整重要度を1/選択肢数で除した。"
  )
  write_csv_and_tex(
    cue_importance,
    file.path(csv_dir, "table_cue_importance.csv"),
    file.path(tex_dir, "table_cue_importance.tex"),
    paste0(study_label, ":政党・経済手がかりの重要度と相対比重"),
    paste0("tab:", study_id, "-cue-importance"),
    notes = "95%信頼区間は条件内で回答者を復元抽出するクラスタ・ブートストラップによる。"
  )
  write_csv_and_tex(
    clogit_table,
    file.path(csv_dir, "table_conditional_logit.csv"),
    file.path(tex_dir, "table_conditional_logit.tex"),
    paste0(study_label, ":条件付きロジット推定"),
    paste0("tab:", study_id, "-conditional-logit"),
    notes = "各選択課題をstratumとするMcFadden型条件付きロジット。標準誤差は回答者単位でクラスタ化した。"
  )
  
  if (nrow(linear_trend_table) > 0) {
    write_csv_and_tex(
      linear_trend_table,
      file.path(csv_dir, "table_amce_linear_trend.csv"),
      file.path(tex_dir, "table_amce_linear_trend.tex"),
      paste0(study_label, ":選択肢数に対するAMCEの線形トレンド"),
      paste0("tab:", study_id, "-amce-linear-trend"),
      notes = "係数は選択肢数が1つ増えたときのAMCEの変化をパーセントポイントで示す。"
    )
  }
  
  if (nrow(party_match_table) > 0) {
    write_csv_and_tex(
      party_match_table,
      file.path(csv_dir, "table_party_match.csv"),
      file.path(tex_dir, "table_party_match.tex"),
      paste0(study_label, ":支持政党と提示政党名の一致効果"),
      paste0("tab:", study_id, "-party-match"),
      notes = "一致効果は、回答者の支持政党と提示された政党名が一致することによる選択確率差。"
    )
  }
  
  balance <- assignment_balance_results[[study_id]]
  balance_summary <- balance$summary %>%
    dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 3)))
  balance_pairwise <- balance$pairwise_smd %>%
    dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 3)))
  
  write_csv_and_tex(
    balance_summary,
    file.path(csv_dir, "table_assignment_balance_summary.csv"),
    file.path(tex_dir, "table_assignment_balance_summary.tex"),
    paste0(study_label, ":条件別の回答者属性"),
    paste0("tab:", study_id, "-balance-summary"),
    notes = "Love plotおよび45度線診断に対応する条件別集計。"
  )
  write_csv_and_tex(
    balance_pairwise,
    file.path(csv_dir, "table_assignment_balance_pairwise_smd.csv"),
    file.path(tex_dir, "table_assignment_balance_pairwise_smd.tex"),
    paste0(study_label, ":全条件ペアの標準化平均差"),
    paste0("tab:", study_id, "-balance-smd"),
    notes = "絶対SMDが0.10未満であれば、通常は実質的に小さい不均衡と解釈される。"
  )
  readr::write_csv(balance$summary, file.path(diag_balance_dir, "assignment_balance_summary.csv"), na = "")
  readr::write_csv(balance$pairwise_smd, file.path(diag_balance_dir, "assignment_balance_pairwise_smd.csv"), na = "")
  readr::write_csv(balance$diagonal_data, file.path(diag_balance_dir, "assignment_balance_diagonal_data.csv"), na = "")
  
  randomization <- profile_randomization_results[[study_id]]
  random_tests <- randomization$uniformity_tests %>%
    dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 4)))
  random_frequency <- randomization$frequency %>%
    dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 4)))
  write_csv_and_tex(
    random_tests,
    file.path(csv_dir, "table_profile_randomization_tests.csv"),
    file.path(tex_dir, "table_profile_randomization_tests.tex"),
    paste0(study_label, ":属性水準提示の一様性検定"),
    paste0("tab:", study_id, "-profile-randomization-tests"),
    notes = "属性×条件ごとのカイ二乗検定。p値はHolm法でも補正した。"
  )
  write_csv_and_tex(
    random_frequency,
    file.path(csv_dir, "table_profile_randomization_frequency.csv"),
    file.path(tex_dir, "table_profile_randomization_frequency.tex"),
    paste0(study_label, ":属性水準の観測比率と設計上の期待比率"),
    paste0("tab:", study_id, "-profile-randomization-frequency"),
    notes = "属性提示の45度線図に対応する数値表。"
  )
  readr::write_csv(randomization$uniformity_tests, file.path(diag_random_dir, "profile_randomization_tests.csv"), na = "")
  readr::write_csv(randomization$frequency, file.path(diag_random_dir, "profile_randomization_frequency.csv"), na = "")
  
  support_amce <- party_support_amce_results[[study_id]]
  if (!is.null(support_amce$subgroup_coefficients)) {
    support_amce_table <- support_amce$subgroup_coefficients %>%
      dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 3)))
    write_csv_and_tex(
      support_amce_table,
      file.path(csv_dir, "table_party_support_amce.csv"),
      file.path(tex_dir, "table_party_support_amce.tex"),
      paste0(study_label, ":支持政党別AMCE"),
      paste0("tab:", study_id, "-party-support-amce"),
      notes = "支持政党別AMCE図に対応する推定値。"
    )
  }
  support_relative <- party_support_relative_cue_results[[study_id]]
  if (!is.null(support_relative$intervals)) {
    support_relative_table <- support_relative$intervals %>%
      dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 3)))
    write_csv_and_tex(
      support_relative_table,
      file.path(csv_dir, "table_party_support_relative_cue.csv"),
      file.path(tex_dir, "table_party_support_relative_cue.tex"),
      paste0(study_label, ":支持政党別の手がかり重要度と相対比重"),
      paste0("tab:", study_id, "-party-support-relative"),
      notes = "支持政党別の相対比重図に対応する回答者クラスタ・ブートストラップ推定。"
    )
  }
  
  study_table_paths[[study_id]] <- list(csv_dir = csv_dir, tex_dir = tex_dir)
}


cross_csv_dir <- file.path(final_dirs$supplement_cross, "tables_csv")
cross_tex_dir <- file.path(final_dirs$supplement_cross, "tables_tex")

cross_tables <- list(
  hypothesis = hypothesis_test_summary,
  adjusted_slopes = choice_set_adjusted_slope_summary,
  cross_relative = cross_study_relative_weight,
  all_party_match_coefficients = study3_all_party_match_results$coefficients,
  all_party_match_trends = study3_all_party_match_results$trends
)

cross_caption <- c(
  hypothesis = "3実験の主要仮説に対応する線形傾向検定",
  adjusted_slopes = "3実験の選択肢数調整済み重要度の線形傾向",
  cross_relative = "3実験横断の政党手がかり相対比重",
  all_party_match_coefficients = "Study 3:すべての対象支持政党における一致効果",
  all_party_match_trends = "Study 3:一致効果の選択肢数トレンド"
)

for (table_name in names(cross_tables)) {
  table_data <- cross_tables[[table_name]]
  if (is.null(table_data)) next
  table_data <- as.data.frame(table_data) %>%
    dplyr::mutate(dplyr::across(where(is.numeric), ~ format_number(.x, 4)))
  write_csv_and_tex(
    table_data,
    file.path(cross_csv_dir, paste0("table_", table_name, ".csv")),
    file.path(cross_tex_dir, paste0("table_", table_name, ".tex")),
    unname(cross_caption[table_name]),
    paste0("tab:cross-", gsub("_", "-", table_name)),
    notes = "対応する補遺図の数値を表形式で再掲した。"
  )
}


for (study_id in names(study_specs)) {
  working_dir <- unified_config[[study_id]]$output_dir
  supplement_fig_dir <- file.path(final_dirs$supplement_root, study_id, "figures")
  copy_files_by_pattern(working_dir, supplement_fig_dir, "\\.(png|pdf)$")
  copy_files_by_pattern(
    working_dir,
    file.path(final_dirs$model_objects_root, study_id),
    "\\.(rds|RDS)$"
  )
  copy_files_by_pattern(working_dir, final_dirs$logs, "(sessionInfo|\\.txt$)")
  
  support_dir <- file.path(unified_output_dir, paste0(study_id, "_party_support"))
  copy_files_by_pattern(support_dir, supplement_fig_dir, "\\.(png|pdf)$")
}

copy_files_by_pattern(
  unified_output_dir,
  file.path(final_dirs$supplement_cross, "figures"),
  "\\.(png|pdf)$"
)
copy_files_by_pattern(unified_output_dir, final_dirs$logs, "(sessionInfo|\\.txt$)")
copy_files_by_pattern(
  unified_output_dir,
  file.path(final_dirs$model_objects_root, "cross_study"),
  "\\.(rds|RDS)$"
)

for (study_id in names(study_specs)) {
  for (kind in c("assignment_balance_love_plot", "assignment_balance_diagonal_plot")) {
    for (extension in c("png", "pdf")) {
      source <- file.path(unified_output_dir, paste0(study_id, "_", kind, ".", extension))
      destination <- file.path(final_dirs$diagnostics_root, study_id, "balance", basename(source))
      copy_file_if_exists(source, destination)
    }
  }
  for (extension in c("png", "pdf")) {
    source <- file.path(unified_output_dir, paste0(study_id, "_profile_randomization_diagonal_plot.", extension))
    destination <- file.path(final_dirs$diagnostics_root, study_id, "randomization", basename(source))
    copy_file_if_exists(source, destination)
  }
}

if (exists("main_text_figure_manifest")) {
  purrr::pwalk(
    main_text_figure_manifest,
    function(figure_number, study, analysis, file_png, file_pdf) {
      prefix <- gsub("[^A-Za-z0-9]+", "_", figure_number)
      if (!is.na(file_png)) {
        copy_file_if_exists(
          file_png,
          file.path(final_dirs$main_figures, paste0(prefix, "_", basename(file_png)))
        )
      }
      if (!is.na(file_pdf)) {
        copy_file_if_exists(
          file_pdf,
          file.path(final_dirs$main_figures, paste0(prefix, "_", basename(file_pdf)))
        )
      }
    }
  )
}

main_table_map <- list(
  study1 = c("table_amce_covariate_adjusted.tex", "table_cue_importance.tex"),
  study2 = c("table_amce_covariate_adjusted.tex", "table_cue_importance.tex"),
  study3 = c("table_amce_covariate_adjusted.tex", "table_cue_importance.tex", "table_party_match.tex")
)
for (study_id in names(main_table_map)) {
  for (table_file in main_table_map[[study_id]]) {
    source <- file.path(final_dirs$supplement_root, study_id, "tables_tex", table_file)
    copy_file_if_exists(
      source,
      file.path(final_dirs$main_tables, paste0(study_id, "_", table_file))
    )
  }
}


pair_manifest <- tibble::tribble(
  ~study_id, ~section_title, ~figure_file, ~table_files,
  "study1", "共変量調整済みAMCE", "amce_cov_facet_model.png", "table_amce_covariate_adjusted.tex",
  "study1", "AMCEヒートマップ", "amce_heatmap_mixed_rank_colored_labels.png", "table_amce_covariate_adjusted.tex",
  "study1", "共変量を含めないAMCE", "amce_facet_nocov.png", "table_amce_unadjusted.tex",
  "study1", "AMCEの条件差", "amce_interaction_difference_from_2party.png", "table_amce_interaction.tex",
  "study1", "条件付きロジット", "clogit_oddsratio_nocov.png", "table_conditional_logit.tex",
  "study1", "手がかり重要度と相対比重", "fig_study1_relative_cue_weight_choice_set_adjusted_jp_bw.png", "table_marginal_means.tex;table_attribute_importance.tex;table_cue_importance.tex",
  "study2", "共変量調整済みAMCE", "amce_cov_facet_model.png", "table_amce_covariate_adjusted.tex",
  "study2", "AMCEヒートマップ", "amce_heatmap_mixed_rank_colored_labels.png", "table_amce_covariate_adjusted.tex",
  "study2", "共変量を含めないAMCE", "amce_facet_nocov.png", "table_amce_unadjusted.tex",
  "study2", "AMCEの条件差", "amce_interaction_difference_from_2party.png", "table_amce_interaction.tex",
  "study2", "条件付きロジット", "clogit_oddsratio_nocov.png", "table_conditional_logit.tex",
  "study2", "手がかり重要度と相対比重", "fig_study2_relative_cue_weight_choice_set_adjusted_jp_bw.png", "table_marginal_means.tex;table_attribute_importance.tex;table_cue_importance.tex",
  "study3", "共変量調整済みAMCE", "amce_cov_facet_model.png", "table_amce_covariate_adjusted.tex",
  "study3", "共変量を含めないAMCE", "amce_nocov_facet_model.png", "table_amce_unadjusted.tex",
  "study3", "AMCEの条件差", "amce_interaction_difference_from_2choice.png", "table_amce_interaction.tex",
  "study3", "AMCEの線形トレンド", "amce_linear_trend.png", "table_amce_linear_trend.tex",
  "study3", "AMCEヒートマップ", "amce_cov_heatmap.png", "table_amce_covariate_adjusted.tex",
  "study3", "条件付きロジット", "clogit_oddsratio_nocov.png", "table_conditional_logit.tex",
  "study3", "支持政党と提示政党名の一致効果", "party_match_effect_combined.png", "table_party_match.tex",
  "study3", "手がかり重要度と相対比重", "fig_study3_relative_cue_weight_choice_set_adjusted_jp_bw.png", "table_marginal_means.tex;table_attribute_importance.tex;table_cue_importance.tex"
)

for (study_id in names(study_specs)) {
  support_figures <- list.files(
    file.path(final_dirs$supplement_root, study_id, "figures"),
    pattern = "party_support_amce_.*\\.png$",
    full.names = FALSE
  )
  if (length(support_figures) > 0) {
    pair_manifest <- dplyr::bind_rows(
      pair_manifest,
      tibble::tibble(
        study_id = study_id,
        section_title = paste0("支持政党別AMCE:", support_figures),
        figure_file = support_figures,
        table_files = "table_party_support_amce.tex"
      )
    )
  }
  if (file.exists(file.path(final_dirs$supplement_root, study_id, "figures", "party_support_relative_cue_weight.png"))) {
    pair_manifest <- dplyr::bind_rows(
      pair_manifest,
      tibble::tibble(
        study_id = study_id,
        section_title = "支持政党別の手がかり相対比重",
        figure_file = "party_support_relative_cue_weight.png",
        table_files = "table_party_support_relative_cue.tex"
      )
    )
  }
}

readr::write_csv(
  pair_manifest,
  file.path(final_dirs$supplement_root, "figure_table_pair_manifest.csv"),
  na = ""
)

pair_tex_lines <- c(
  "% Generated automatically. Run LuaLaTeX from the supplement directory.",
  "\\providecommand{\\ConjointSupplementRoot}{.}",
  "\\section{標本構築・データ品質・分析結果}"
)

for (study_id in names(study_specs)) {
  study_label <- study_specs[[study_id]]$study_label
  pair_tex_lines <- c(
    pair_tex_lines,
    paste0("\\section{", latex_escape(study_label), "}"),
    "\\subsection{標本構築とスクリーニング}",
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_sample_attrition.tex}"),
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_sample_attrition_by_condition.tex}"),
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_manipulation_check.tex}"),
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_attention_check.tex}"),
    "\\clearpage",
    "\\subsection{回答者割付のバランス}",
    "\\begin{figure}[p]",
    "\\centering",
    paste0(
      "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/../diagnostics/",
      study_id,
      "/balance/",
      study_id,
      "_assignment_balance_love_plot.png}"
    ),
    paste0("\\caption{", latex_escape(study_label), ":回答者割付のLove plot}"),
    "\\end{figure}",
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_assignment_balance_pairwise_smd.tex}"),
    "\\begin{figure}[p]",
    "\\centering",
    paste0(
      "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/../diagnostics/",
      study_id,
      "/balance/",
      study_id,
      "_assignment_balance_diagonal_plot.png}"
    ),
    paste0("\\caption{", latex_escape(study_label), ":条件別共変量平均の45度線診断}"),
    "\\end{figure}",
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_assignment_balance_summary.tex}"),
    "\\clearpage",
    "\\subsection{コンジョイント属性提示の無作為化診断}",
    "\\begin{figure}[p]",
    "\\centering",
    paste0(
      "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/../diagnostics/",
      study_id,
      "/randomization/",
      study_id,
      "_profile_randomization_diagonal_plot.png}"
    ),
    paste0("\\caption{", latex_escape(study_label), ":属性水準の観測比率と期待比率}"),
    "\\end{figure}",
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_profile_randomization_tests.tex}"),
    paste0("\\input{\\ConjointSupplementRoot/", study_id, "/tables_tex/table_profile_randomization_frequency.tex}"),
    "\\clearpage",
    "\\subsection{推定結果:図と対応する表}"
  )
  
  study_pairs <- pair_manifest %>% dplyr::filter(.data$study_id == study_id)
  for (i in seq_len(nrow(study_pairs))) {
    row <- study_pairs[i, ]
    figure_path <- file.path(row$study_id, "figures", row$figure_file)
    tables <- unlist(strsplit(row$table_files, ";", fixed = TRUE))
    pair_tex_lines <- c(
      pair_tex_lines,
      paste0("\\subsubsection{", latex_escape(row$section_title), "}"),
      "\\begin{figure}[p]",
      "\\centering",
      paste0("\\includegraphics[width=0.96\\linewidth]{\\ConjointSupplementRoot/", gsub("\\\\", "/", figure_path), "}"),
      paste0("\\caption{", latex_escape(row$section_title), "}"),
      "\\end{figure}"
    )
    for (table_file in tables) {
      table_path <- file.path(row$study_id, "tables_tex", table_file)
      if (file.exists(file.path(final_dirs$supplement_root, table_path))) {
        pair_tex_lines <- c(
          pair_tex_lines,
          paste0("\\input{\\ConjointSupplementRoot/", gsub("\\\\", "/", table_path), "}")
        )
      }
    }
    pair_tex_lines <- c(pair_tex_lines, "\\clearpage")
  }
}

pair_tex_lines <- c(
  pair_tex_lines,
  "\\section{3実験横断の分析}",
  "\\subsection{主要仮説の線形傾向検定}",
  "\\begin{figure}[p]",
  "\\centering",
  "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/cross_study/figures/fig_supp_hypothesis_linear_trend_tests.png}",
  "\\caption{3実験の主要仮説に対応する線形傾向検定}",
  "\\end{figure}",
  "\\input{\\ConjointSupplementRoot/cross_study/tables_tex/table_hypothesis.tex}",
  "\\clearpage",
  "\\subsection{選択肢数調整済み重要度の線形傾向}",
  "\\begin{figure}[p]",
  "\\centering",
  "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/cross_study/figures/fig_supp_choice_set_adjusted_importance_slopes.png}",
  "\\caption{3実験の選択肢数調整済み重要度の線形傾向}",
  "\\end{figure}",
  "\\input{\\ConjointSupplementRoot/cross_study/tables_tex/table_adjusted_slopes.tex}",
  "\\clearpage",
  "\\subsection{3実験横断の政党手がかり相対比重}",
  "\\begin{figure}[p]",
  "\\centering",
  "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/cross_study/figures/fig_supp_cross_study_relative_party_weight.png}",
  "\\caption{3実験横断の政党手がかり相対比重}",
  "\\end{figure}",
  "\\input{\\ConjointSupplementRoot/cross_study/tables_tex/table_cross_relative.tex}",
  "\\clearpage"
)

if (file.exists(file.path(final_dirs$supplement_cross, "figures", "party_match_all_parties.png"))) {
  pair_tex_lines <- c(
    pair_tex_lines,
    "\\subsection{Study 3:すべての対象支持政党における一致効果}",
    "\\begin{figure}[p]",
    "\\centering",
    "\\includegraphics[width=0.92\\linewidth]{\\ConjointSupplementRoot/cross_study/figures/party_match_all_parties.png}",
    "\\caption{すべての対象支持政党における支持政党名一致効果}",
    "\\end{figure}",
    "\\input{\\ConjointSupplementRoot/cross_study/tables_tex/table_all_party_match_coefficients.tex}",
    "\\input{\\ConjointSupplementRoot/cross_study/tables_tex/table_all_party_match_trends.tex}",
    "\\clearpage"
  )
}

writeLines(
  pair_tex_lines,
  con = file.path(final_dirs$supplement_root, "all_studies_figure_table_pairs.tex"),
  useBytes = TRUE
)

preamble_lines <- c(
  "% Add these packages to the preamble of appendix.tex.",
  "\\usepackage{graphicx}",
  "\\usepackage{booktabs}",
  "\\usepackage{longtable}",
  "\\usepackage{array}",
  "\\usepackage{pdflscape}",
  "\\usepackage{caption}",
  "% Compile with LuaLaTeX because the generated captions and tables contain Japanese."
)
writeLines(
  preamble_lines,
  con = file.path(final_dirs$supplement_root, "latex_preamble_snippet.tex"),
  useBytes = TRUE
)

standalone_lines <- c(
  "% !TeX program = lualatex",
  "\\documentclass[a4paper,11pt]{ltjsarticle}",
  "\\usepackage[margin=22mm]{geometry}",
  "\\usepackage{graphicx}",
  "\\usepackage{booktabs}",
  "\\usepackage{longtable}",
  "\\usepackage{array}",
  "\\usepackage{pdflscape}",
  "\\usepackage{caption}",
  "\\begin{document}",
  "\\tableofcontents",
  "\\clearpage",
  "\\input{all_studies_figure_table_pairs.tex}",
  "\\end{document}"
)
writeLines(
  standalone_lines,
  con = file.path(final_dirs$supplement_root, "supplement_tables_figures_master.tex"),
  useBytes = TRUE
)

layout_lines <- c(
  "OUTPUT DIRECTORY STRUCTURE",
  "==========================",
  "main_text/figures      : manuscript figures",
  "main_text/tables       : LaTeX tables corresponding to manuscript figures",
  "supplement/study1-3    : per-study figures, CSV tables, and LaTeX tables",
  "supplement/cross_study : cross-study figures and tables",
  "diagnostics/study1-3   : respondent screening, balance, and randomization diagnostics",
  "model_objects          : RDS model and analysis objects",
  "logs                   : text model summaries and session information",
  "_working               : original intermediate outputs produced by each analysis module",
  "",
  "LATEX",
  "-----",
  "Add the packages in supplement/latex_preamble_snippet.tex to appendix.tex.",
  "Then input supplement/all_studies_figure_table_pairs.tex, or compile",
  "supplement/supplement_tables_figures_master.tex with LuaLaTeX."
)
writeLines(
  layout_lines,
  con = file.path(final_output_root, "OUTPUT_STRUCTURE_AND_LATEX_README.txt"),
  useBytes = TRUE
)

saveRDS(
  list(
    screening = screening_results,
    pair_manifest = pair_manifest,
    final_dirs = final_dirs
  ),
  file = file.path(final_dirs$model_objects_root, "screening_and_latex_export_objects.rds")
)

cat(
  "\nScreened-sample audit, LaTeX tables, figure-table pairs, and final output organization completed.\n",
  "Final output root: ", normalizePath(final_output_root), "\n",
  "LaTeX master: ",
  normalizePath(file.path(final_dirs$supplement_root, "supplement_tables_figures_master.tex")),
  "\n",
  sep = ""
)

B. 推定方法と分析標本の定義

B.1 分析標本

各回答者は2、3、4、5のいずれかの選択肢数条件に割り当てられ、5つの選択課題に回答した。従属変数は、各課題に提示されたプロフィールが選択された場合に1、選択されなかった場合に0をとる二値変数である。

実験1では、初回同意、最終送信同意、および割り当てられた条件における5課題の有効回答を満たす回答者を分析対象とした。実験2・3では、これらに加えて、イデオロギー行列中の指示項目と選択肢数の操作確認質問に正答した回答者に限定した。

B.2 AMCE

回答者を \(i\)、選択課題を \(t\)、プロフィールを \(j\)、選択肢数条件を \(n\in\{2,3,4,5\}\) とする。従属変数を

\[ Y_{itj} = \mathbf{1}\{\text{プロフィール }j\text{ が選択された}\} \]

と定義する。各選択肢数条件について、線形確率モデルを別々に推定する。

\[ Y_{itj} = \alpha_n + \sum_{a} \sum_{\ell\neq \ell_{a0}} \beta_{n,a\ell}D_{itj,a\ell} + \boldsymbol{\gamma}_{n}^{\prime}\boldsymbol{Z}_{i} + \varepsilon_{itj}. \]

\(\beta_{n,a\ell}\) は、属性 \(a\) を基準水準 \(\ell_{a0}\) から水準 \(\ell\) に変更したときの平均限界要素効果(AMCE)である。標準誤差は回答者単位でクラスタ化した。

実験1・2では、政策位置の基準を中道、与野党地位の基準を野党、議席数の基準を10以下とし、GDP成長率、日経平均株価、CPI、失業率はいずれも変化なしを基準とした。実験3では政党名の基準を自由民主党とした。

B.3 限界平均と属性重要度

選択肢数条件 \(n\) における属性 \(a\) の水準 \(\ell\) の限界平均を、

\[ \widehat{\mu}_{n,a\ell} = \frac{ \sum_{i,t,j} \mathbf{1}\{X_{itj,a}=\ell\}Y_{itj} }{ \sum_{i,t,j} \mathbf{1}\{X_{itj,a}=\ell\} } \]

とする。

属性 \(a\)\(L_a\) 個の水準をもつとき、属性重要度を全水準ペアの限界平均差の絶対値の平均として、

\[ \widehat{I}_{n,a} = \binom{L_a}{2}^{-1} \sum_{\ell<\ell'} \left| \widehat{\mu}_{n,a\ell} - \widehat{\mu}_{n,a\ell'} \right| \]

と定義した。

実験1・2の政党手がかりの重要度は、政策位置、与野党地位、議席数の3属性の重要度を等しい加重で平均した。実験3では政党名属性の重要度を政党手がかりの重要度とした。経済手がかりは、3実験ともGDP成長率、日経平均株価、CPI、失業率の4属性の重要度を等しい加重で平均した。

B.4 選択肢数調整済み重要度と相対比重

\(k\) 個のプロフィールから必ず1つを選択するため、プロフィール1件あたりの平均選択確率は \(1/k\) となる。条件間比較のため、選択肢数調整済み重要度を、

\[ \widehat{I}^{\mathrm{adj}}_{k,a} = \frac{\widehat{I}_{k,a}}{1/k} = k\widehat{I}_{k,a} \]

とした。

政党手がかりの重要度を \(\widehat{P}_{k}\)、経済手がかりの重要度を \(\widehat{E}_{k}\) とすると、政党手がかりの相対比重は、

\[ \widehat{W}_{k} = \frac{\widehat{P}_{k}} {\widehat{P}_{k}+\widehat{E}_{k}} \]

である。政党・経済の両重要度に同じ \(k\) を乗じても相対比重は変化しない。

B.5 ブートストラップと線形トレンド

重要度と相対比重の95%信頼区間は、各選択肢数条件内で回答者を単位として復元抽出し、各回答者の5課題・全プロフィールに欠損のない回答者クラスター・ブートストラップから算出した。主要分析では2,000回反復させた。

各指標 \(Q_n\) の選択肢数に対する線形傾向は、

\[ Q_n=\eta+\delta n+u_n \]

として4条件の点推定値にOLSを当てはめ、傾き \(\delta\) を求めた。各ブートストラップ反復でも同じ傾きを再推定し、95%信頼区間と両側ブートストラップ \(p\) 値を算出した。H1a、H1b、H2a、H2bの判定には選択肢数調整済み重要度を用いた。

B.6 条件付きロジット

強制選択課題の構造を考慮する頑健性分析として、各選択肢数条件について条件付きロジットを推定した。

\[ \Pr(Y_{itj}=1\mid \mathcal{C}_{it}) = \frac{\exp(\boldsymbol{X}_{itj}^{\prime}\boldsymbol{\beta})} {\sum_{k\in\mathcal{C}_{it}}\exp(\boldsymbol{X}_{itk}^{\prime}\boldsymbol{\beta})}. \]

課題を層(stratum)とし、回答者単位でクラスタ化した。回答者レベル共変量は同一選択課題内で一定であるため、条件付きロジットにはプロフィール属性のみを投入した。

B.7 支持政党名との一致効果

実験3では、

\[ M_{itj} = \mathbf{1}\{\text{提示政党名}_{itj}=\text{支持政党}_{i}\} \]

を作成した。全体モデルでは、支持政党名一致、提示政党名、4つの経済属性を投入し、選択肢数条件ごとに推定した。なお、支持政党別の分析では、政党名と一致指標が完全に対応してしまうため、政党名主効果を除き、一致指標と経済属性を用いた。

B.8 バランスと無作為化診断

回答者割付のバランスは、2、3、4、5条件の全条件ペアについて標準化平均差を算出した。用いた回答者属性は、各実験で利用可能な性別、年齢、4年制大学以上、対数世帯年収、自己イデオロギー、およびそれらの欠損指標と支持政党である。地域・都道府県はこの割付バランス診断には用いていない。Love plot は全6条件ペアの絶対SMDを示し、対角線図は同じ回答者共変量について各条件平均を標準化し、二条件ずつ45度線と比較する補助的な可視化である。

\[ \mathrm{SMD}_{ab} = \frac{\overline{x}_a-\overline{x}_b} {\sqrt{(s_a^2+s_b^2)/2}}. \]

プロフィール属性の提示については、選択肢数条件×属性×水準ごとに観測比率を求め、水準数を \(L_a\) とした設計上の期待比率 \(1/L_a\) と比較した。属性×条件ごとに一様分布を帰無仮説とするカイ二乗検定を行い、Holm法による補正値も報告した。

C. 無作為化についての各種検討

以下で、回答者レベルの割付バランスとプロフィール属性の無作為提示は別々に確認する。回答者レベルではLove plotと45度線診断を併用し、プロフィールレベルでは各属性水準の観測比率を設計上の期待比率と比較する。

B.1 実験1(2023年)

図C1:回答者割付のLove plot

実験1仕様 <- study_specs$study1
実験1割付設計 <- make_balance_design(実験1仕様)
実験1SMD <- pairwise_smd_multiarm(実験1割付設計$long)
実験1最大SMD <- 実験1SMD %>%
  dplyr::group_by(variable, label) %>%
  dplyr::summarise(max_abs_smd = max(abs_smd, na.rm = TRUE), .groups = "drop")

Loveデータ <- 実験1SMD %>%
  dplyr::left_join(実験1最大SMD, by = c("variable", "label")) %>%
  dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd))

図C1 <- ggplot2::ggplot(Loveデータ, ggplot2::aes(x = abs_smd, y = 表示名)) +
  ggplot2::geom_vline(xintercept = 0.10, linetype = "dashed", linewidth = 0.55) +
  ggplot2::geom_point(alpha = 0.30, size = 1.4, position = ggplot2::position_jitter(height = 0.10, width = 0)) +
  ggplot2::geom_point(
    data = 実験1最大SMD %>% dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd)),
    ggplot2::aes(x = max_abs_smd, y = 表示名),
    inherit.aes = FALSE, shape = 21, fill = "white", size = 2.5, stroke = 0.8
  ) +
  ggplot2::labs(x = "条件間の絶対標準化平均差(|SMD|)", y = NULL,
                subtitle = "実験1(2023年):各点は条件ペア、白抜き点は最大絶対SMD") +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C1

表C1には図C1の各点に対応する。各行には比較する2条件の平均とSMDを示す。

表C1 <- 実験1SMD %>%
  dplyr::transmute(
    変数 = label,
    比較 = paste0(condition_a, "政党条件-", condition_b, "政党条件"),
    `前者の平均` = round(mean_a, 3),
    `後者の平均` = round(mean_b, 3),
    `前者N` = n_a,
    `後者N` = n_b,
    SMD = round(smd, 3),
    `|SMD|` = round(abs_smd, 3)
  )
knitr::kable(表日本語(表C1), format = "html", row.names = FALSE)
変数 比較 前者の平均 後者の平均 前者N 後者N SMD |SMD|
年齢 2政党条件-3政党条件 35.374 34.896 815 843 0.049 0.049
女性 2政党条件-3政党条件 0.297 0.305 815 843 -0.017 0.017
性別:欠損 2政党条件-3政党条件 0.021 0.017 815 843 0.031 0.031
世帯年収(対数) 2政党条件-3政党条件 5.890 6.068 815 843 -0.133 0.133
支持政党:公明党 2政党条件-3政党条件 0.189 0.168 815 843 0.054 0.054
支持政党:国民民主党 2政党条件-3政党条件 0.000 0.002 815 843 -0.069 0.069
支持政党:日本共産党 2政党条件-3政党条件 0.055 0.058 815 843 -0.013 0.013
支持政党:日本維新の会 2政党条件-3政党条件 0.499 0.509 815 843 -0.019 0.019
支持政党:社会民主党 2政党条件-3政党条件 0.009 0.013 815 843 -0.043 0.043
支持政党:立憲民主党 2政党条件-3政党条件 0.240 0.238 815 843 0.005 0.005
支持政党:自由民主党 2政党条件-3政党条件 0.007 0.011 815 843 -0.035 0.035
年齢 2政党条件-4政党条件 35.374 35.760 815 882 -0.040 0.040
女性 2政党条件-4政党条件 0.297 0.296 815 882 0.002 0.002
性別:欠損 2政党条件-4政党条件 0.021 0.018 815 882 0.020 0.020
世帯年収(対数) 2政党条件-4政党条件 5.890 6.007 815 882 -0.084 0.084
支持政党:公明党 2政党条件-4政党条件 0.189 0.202 815 882 -0.032 0.032
支持政党:国民民主党 2政党条件-4政党条件 0.000 0.002 815 882 -0.067 0.067
支持政党:日本共産党 2政党条件-4政党条件 0.055 0.084 815 882 -0.113 0.113
支持政党:日本維新の会 2政党条件-4政党条件 0.499 0.456 815 882 0.087 0.087
支持政党:社会民主党 2政党条件-4政党条件 0.009 0.015 815 882 -0.057 0.057
支持政党:立憲民主党 2政党条件-4政党条件 0.240 0.240 815 882 0.000 0.000
支持政党:自由民主党 2政党条件-4政党条件 0.007 0.001 815 882 0.096 0.096
年齢 2政党条件-5政党条件 35.374 34.901 815 842 0.048 0.048
女性 2政党条件-5政党条件 0.297 0.293 815 842 0.008 0.008
性別:欠損 2政党条件-5政党条件 0.021 0.018 815 842 0.022 0.022
世帯年収(対数) 2政党条件-5政党条件 5.890 6.033 815 842 -0.105 0.105
支持政党:公明党 2政党条件-5政党条件 0.189 0.185 815 842 0.009 0.009
支持政党:国民民主党 2政党条件-5政党条件 0.000 0.002 815 842 -0.069 0.069
支持政党:日本共産党 2政党条件-5政党条件 0.055 0.065 815 842 -0.042 0.042
支持政党:日本維新の会 2政党条件-5政党条件 0.499 0.458 815 842 0.082 0.082
支持政党:社会民主党 2政党条件-5政党条件 0.009 0.010 815 842 -0.010 0.010
支持政党:立憲民主党 2政党条件-5政党条件 0.240 0.278 815 842 -0.085 0.085
支持政党:自由民主党 2政党条件-5政党条件 0.007 0.001 815 842 0.095 0.095
年齢 3政党条件-4政党条件 34.896 35.760 843 882 -0.090 0.090
女性 3政党条件-4政党条件 0.305 0.296 843 882 0.020 0.020
性別:欠損 3政党条件-4政党条件 0.017 0.018 843 882 -0.012 0.012
世帯年収(対数) 3政党条件-4政党条件 6.068 6.007 843 882 0.049 0.049
支持政党:公明党 3政党条件-4政党条件 0.168 0.202 843 882 -0.086 0.086
支持政党:国民民主党 3政党条件-4政党条件 0.002 0.002 843 882 0.002 0.002
支持政党:日本共産党 3政党条件-4政党条件 0.058 0.084 843 882 -0.100 0.100
支持政党:日本維新の会 3政党条件-4政党条件 0.509 0.456 843 882 0.106 0.106
支持政党:社会民主党 3政党条件-4政党条件 0.013 0.015 843 882 -0.014 0.014
支持政党:立憲民主党 3政党条件-4政党条件 0.238 0.240 843 882 -0.005 0.005
支持政党:自由民主党 3政党条件-4政党条件 0.011 0.001 843 882 0.125 0.125
年齢 3政党条件-5政党条件 34.896 34.901 843 842 -0.001 0.001
女性 3政党条件-5政党条件 0.305 0.293 843 842 0.025 0.025
性別:欠損 3政党条件-5政党条件 0.017 0.018 843 842 -0.009 0.009
世帯年収(対数) 3政党条件-5政党条件 6.068 6.033 843 842 0.029 0.029
支持政党:公明党 3政党条件-5政党条件 0.168 0.185 843 842 -0.044 0.044
支持政党:国民民主党 3政党条件-5政党条件 0.002 0.002 843 842 0.000 0.000
支持政党:日本共産党 3政党条件-5政党条件 0.058 0.065 843 842 -0.030 0.030
支持政党:日本維新の会 3政党条件-5政党条件 0.509 0.458 843 842 0.101 0.101
支持政党:社会民主党 3政党条件-5政党条件 0.013 0.010 843 842 0.034 0.034
支持政党:立憲民主党 3政党条件-5政党条件 0.238 0.278 843 842 -0.090 0.090
支持政党:自由民主党 3政党条件-5政党条件 0.011 0.001 843 842 0.124 0.124
年齢 4政党条件-5政党条件 35.760 34.901 882 842 0.089 0.089
女性 4政党条件-5政党条件 0.296 0.293 882 842 0.006 0.006
性別:欠損 4政党条件-5政党条件 0.018 0.018 882 842 0.002 0.002
世帯年収(対数) 4政党条件-5政党条件 6.007 6.033 882 842 -0.020 0.020
支持政党:公明党 4政党条件-5政党条件 0.202 0.185 882 842 0.042 0.042
支持政党:国民民主党 4政党条件-5政党条件 0.002 0.002 882 842 -0.002 0.002
支持政党:日本共産党 4政党条件-5政党条件 0.084 0.065 882 842 0.071 0.071
支持政党:日本維新の会 4政党条件-5政党条件 0.456 0.458 882 842 -0.005 0.005
支持政党:社会民主党 4政党条件-5政党条件 0.015 0.010 882 842 0.048 0.048
支持政党:立憲民主党 4政党条件-5政党条件 0.240 0.278 882 842 -0.086 0.086
支持政党:自由民主党 4政党条件-5政党条件 0.001 0.001 882 842 -0.002 0.002

図C2:条件平均の45度線診断

図C2は図C1と同じ回答者レベルの割付バランスを、各共変量の条件平均を標準化したうえで二条件ずつ45度線と比較したものである。

対角線データ <- assignment_balance_results$study1$diagonal_data %>%
  dplyr::mutate(
    比較 = paste0(condition_a, "政党条件-", condition_b, "政党条件")
  )

ラベル対象 <- 対角線データ %>%
  dplyr::group_by(比較) %>%
  dplyr::slice_max(abs_diagonal_deviation, n = 3, with_ties = FALSE) %>%
  dplyr::ungroup()

軸範囲 <- max(abs(c(対角線データ$x_mean, 対角線データ$y_mean)), na.rm = TRUE)
軸範囲 <- max(0.10, 軸範囲 * 1.15)

図C2 <- ggplot2::ggplot(対角線データ, ggplot2::aes(x = x_mean, y = y_mean)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.60) +
  ggplot2::geom_hline(yintercept = 0, linewidth = 0.25) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.25) +
  ggplot2::geom_point(shape = 21, fill = "white", size = 2.2) +
  ggplot2::geom_text(data = ラベル対象, ggplot2::aes(label = label), size = 2.6, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 比較, ncol = 3) +
  ggplot2::coord_equal(xlim = c(-軸範囲, 軸範囲), ylim = c(-軸範囲, 軸範囲)) +
  ggplot2::labs(x = "左側条件の標準化共変量平均", y = "右側条件の標準化共変量平均") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C2

表C2 <- assignment_balance_results$study1$summary %>%
  dplyr::transmute(
    変数 = label,
    `2政党条件の平均` = round(mean_condition_2, 3),
    `3政党条件の平均` = round(mean_condition_3, 3),
    `4政党条件の平均` = round(mean_condition_4, 3),
    `5政党条件の平均` = round(mean_condition_5, 3),
    `最大|SMD|` = round(max_abs_smd, 3),
    `Holm補正p値` = signif(p_holm, 3)
  )
knitr::kable(表日本語(表C2), format = "html", row.names = FALSE)
変数 2政党条件の平均 3政党条件の平均 4政党条件の平均 5政党条件の平均 最大|SMD| Holm補正p値
世帯年収(対数) 5.890 6.068 6.007 6.033 0.133 0.336
支持政党:自由民主党 0.007 0.011 0.001 0.001 0.125 0.106
支持政党:日本共産党 0.055 0.058 0.084 0.065 0.113 0.580
支持政党:日本維新の会 0.499 0.509 0.456 0.458 0.106 0.476
年齢 35.374 34.896 35.760 34.901 0.090 1.000
支持政党:立憲民主党 0.240 0.238 0.240 0.278 0.090 1.000
支持政党:公明党 0.189 0.168 0.202 0.185 0.086 1.000
支持政党:国民民主党 0.000 0.002 0.002 0.002 0.069 1.000
支持政党:社会民主党 0.009 0.013 0.015 0.010 0.057 1.000
性別:欠損 0.021 0.017 0.018 0.018 0.031 1.000
女性 0.297 0.305 0.296 0.293 0.025 1.000

図C3:プロフィール属性水準の無作為提示

図C3は回答者の条件割付ではなく、各コンジョイント課題内で属性水準が設計どおり一様に提示されているかを確認したものである。

属性頻度 <- profile_randomization_results$study1$frequency %>%
  dplyr::mutate(
    属性 = 属性日本語(attribute),
    条件 = 条件日本語(party_n, "study1")
  )

表示ラベル <- 属性頻度 %>%
  dplyr::group_by(属性, 条件) %>%
  dplyr::slice_max(abs_deviation, n = 2, with_ties = FALSE) %>%
  dplyr::ungroup()

図C3 <- ggplot2::ggplot(属性頻度, ggplot2::aes(x = expected_share, y = observed_share, shape = 条件)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.65) +
  ggplot2::geom_point(size = 2.2, fill = "white") +
  ggplot2::geom_text(data = 表示ラベル, ggplot2::aes(label = level), size = 2.4, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 属性, ncol = 3) +
  ggplot2::coord_equal() +
  ggplot2::labs(x = "設計上の期待比率", y = "観測比率", shape = "条件") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank(), legend.position = "bottom")
図C3

表C3 <- profile_randomization_results$study1$uniformity_tests %>%
  dplyr::transmute(
    条件 = 条件日本語(party_n, "study1"),
    属性 = 属性日本語(attribute),
    `カイ二乗値` = round(chi_square, 3),
    自由度 = df,
    p値 = signif(p_value, 3),
    `Holm補正p値` = signif(p_holm, 3),
    `最大絶対比率差` = round(max_abs_share_deviation, 4)
  )
knitr::kable(表日本語(表C3), format = "html", row.names = FALSE)
条件 属性 カイ二乗値 自由度 p値 Holm補正p値 最大絶対比率差
2政党条件 消費者物価指数(CPI) 2.339 2 3.110000e-01 1.000000e+00 0.0078
2政党条件 GDP成長率 4.032 2 1.330000e-01 1.000000e+00 0.0091
2政党条件 与野党地位 2.474 1 1.160000e-01 1.000000e+00 0.0087
2政党条件 日経平均株価 0.108 2 9.480000e-01 1.000000e+00 0.0017
2政党条件 政策位置 0.022 2 9.890000e-01 1.000000e+00 0.0007
2政党条件 衆議院議席数 6.683 4 1.540000e-01 1.000000e+00 0.0080
2政党条件 失業率 1.851 2 3.960000e-01 1.000000e+00 0.0071
3政党条件 消費者物価指数(CPI) 1.489 2 4.750000e-01 1.000000e+00 0.0049
3政党条件 GDP成長率 7.043 2 2.950000e-02 6.500000e-01 0.0111
3政党条件 与野党地位 1476.555 1 4.940656e-323 1.240105e-321 0.1709
3政党条件 日経平均株価 1.700 2 4.270000e-01 1.000000e+00 0.0055
3政党条件 政策位置 4.462 2 1.070000e-01 1.000000e+00 0.0081
3政党条件 衆議院議席数 209.363 4 3.640000e-44 8.380000e-43 0.0335
3政党条件 失業率 1.219 2 5.440000e-01 1.000000e+00 0.0042
4政党条件 消費者物価指数(CPI) 4.270 2 1.180000e-01 1.000000e+00 0.0073
4政党条件 GDP成長率 0.127 2 9.390000e-01 1.000000e+00 0.0012
4政党条件 与野党地位 4587.756 1 0.000000e+00 0.000000e+00 0.2550
4政党条件 日経平均株価 1.221 2 5.430000e-01 1.000000e+00 0.0037
4政党条件 政策位置 4.136 2 1.260000e-01 1.000000e+00 0.0070
4政党条件 衆議院議席数 896.584 4 9.160000e-193 2.200000e-191 0.0739
4政党条件 失業率 0.551 2 7.590000e-01 1.000000e+00 0.0025
5政党条件 消費者物価指数(CPI) 2.511 2 2.850000e-01 1.000000e+00 0.0051
5政党条件 GDP成長率 3.062 2 2.160000e-01 1.000000e+00 0.0056
5政党条件 与野党地位 7618.855 1 0.000000e+00 0.000000e+00 0.3008
5政党条件 日経平均株価 1.781 2 4.100000e-01 1.000000e+00 0.0041
5政党条件 政策位置 0.632 2 7.290000e-01 1.000000e+00 0.0025
5政党条件 衆議院議席数 3958.393 4 0.000000e+00 0.000000e+00 0.1051
5政党条件 失業率 6.864 2 3.230000e-02 6.790000e-01 0.0079
表C4 <- 属性頻度 %>%
  dplyr::transmute(
    条件,
    属性,
    水準 = level,
    観測数 = observed_n,
    総数 = total_n,
    観測比率 = round(observed_share, 4),
    期待比率 = round(expected_share, 4),
= round(deviation, 4)
  )
knitr::kable(表日本語(表C4), format = "html", row.names = FALSE)
条件 属性 水準 観測数 総数 観測比率 期待比率
2政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 2672 8150 0.3279 0.3333 -0.0055
2政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 2780 8150 0.3411 0.3333 0.0078
2政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 2698 8150 0.3310 0.3333 -0.0023
2政党条件 GDP成長率 GDP成長率±0% 2716 8150 0.3333 0.3333 -0.0001
2政党条件 GDP成長率 GDP成長率プラス1% 2791 8150 0.3425 0.3333 0.0091
2政党条件 GDP成長率 GDP成長率マイナス1% 2643 8150 0.3243 0.3333 -0.0090
2政党条件 与野党地位 与党 4146 8150 0.5087 0.5000 0.0087
2政党条件 与野党地位 野党 4004 8150 0.4913 0.5000 -0.0087
2政党条件 日経平均株価 日経平均前月同期比プラス1000円 2721 8150 0.3339 0.3333 0.0005
2政党条件 日経平均株価 日経平均前月同期比マイナス1000円 2726 8150 0.3345 0.3333 0.0011
2政党条件 日経平均株価 日経平均前月同期比変わらず 2703 8150 0.3317 0.3333 -0.0017
2政党条件 政策位置 中道 2717 8150 0.3334 0.3333 0.0000
2政党条件 政策位置 右派・保守的 2711 8150 0.3326 0.3333 -0.0007
2政党条件 政策位置 左派・革新的 2722 8150 0.3340 0.3333 0.0007
2政党条件 衆議院議席数 100~199 1662 8150 0.2039 0.2000 0.0039
2政党条件 衆議院議席数 10~49 1565 8150 0.1920 0.2000 -0.0080
2政党条件 衆議院議席数 10以下 1686 8150 0.2069 0.2000 0.0069
2政党条件 衆議院議席数 200以上 1652 8150 0.2027 0.2000 0.0027
2政党条件 衆議院議席数 50~99 1585 8150 0.1945 0.2000 -0.0055
2政党条件 失業率 失業率前期比±0% 2750 8150 0.3374 0.3333 0.0041
2政党条件 失業率 失業率前期比プラス1% 2741 8150 0.3363 0.3333 0.0030
2政党条件 失業率 失業率前期比マイナス1% 2659 8150 0.3263 0.3333 -0.0071
3政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 4168 12645 0.3296 0.3333 -0.0037
3政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 4277 12645 0.3382 0.3333 0.0049
3政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 4200 12645 0.3321 0.3333 -0.0012
3政党条件 GDP成長率 GDP成長率±0% 4297 12645 0.3398 0.3333 0.0065
3政党条件 GDP成長率 GDP成長率プラス1% 4075 12645 0.3223 0.3333 -0.0111
3政党条件 GDP成長率 GDP成長率マイナス1% 4273 12645 0.3379 0.3333 0.0046
3政党条件 与野党地位 与党 4162 12645 0.3291 0.5000 -0.1709
3政党条件 与野党地位 野党 8483 12645 0.6709 0.5000 0.1709
3政党条件 日経平均株価 日経平均前月同期比プラス1000円 4177 12645 0.3303 0.3333 -0.0030
3政党条件 日経平均株価 日経平均前月同期比マイナス1000円 4284 12645 0.3388 0.3333 0.0055
3政党条件 日経平均株価 日経平均前月同期比変わらず 4184 12645 0.3309 0.3333 -0.0025
3政党条件 政策位置 中道 4113 12645 0.3253 0.3333 -0.0081
3政党条件 政策位置 右派・保守的 4306 12645 0.3405 0.3333 0.0072
3政党条件 政策位置 左派・革新的 4226 12645 0.3342 0.3333 0.0009
3政党条件 衆議院議席数 100~199 2105 12645 0.1665 0.2000 -0.0335
3政党条件 衆議院議席数 10~49 2802 12645 0.2216 0.2000 0.0216
3政党条件 衆議院議席数 10以下 2794 12645 0.2210 0.2000 0.0210
3政党条件 衆議院議席数 200以上 2157 12645 0.1706 0.2000 -0.0294
3政党条件 衆議院議席数 50~99 2787 12645 0.2204 0.2000 0.0204
3政党条件 失業率 失業率前期比±0% 4268 12645 0.3375 0.3333 0.0042
3政党条件 失業率 失業率前期比プラス1% 4167 12645 0.3295 0.3333 -0.0038
3政党条件 失業率 失業率前期比マイナス1% 4210 12645 0.3329 0.3333 -0.0004
4政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 6009 17640 0.3406 0.3333 0.0073
4政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 5824 17640 0.3302 0.3333 -0.0032
4政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 5807 17640 0.3292 0.3333 -0.0041
4政党条件 GDP成長率 GDP成長率±0% 5894 17640 0.3341 0.3333 0.0008
4政党条件 GDP成長率 GDP成長率プラス1% 5858 17640 0.3321 0.3333 -0.0012
4政党条件 GDP成長率 GDP成長率マイナス1% 5888 17640 0.3338 0.3333 0.0005
4政党条件 与野党地位 与党 4322 17640 0.2450 0.5000 -0.2550
4政党条件 与野党地位 野党 13318 17640 0.7550 0.5000 0.2550
4政党条件 日経平均株価 日経平均前月同期比プラス1000円 5814 17640 0.3296 0.3333 -0.0037
4政党条件 日経平均株価 日経平均前月同期比マイナス1000円 5931 17640 0.3362 0.3333 0.0029
4政党条件 日経平均株価 日経平均前月同期比変わらず 5895 17640 0.3342 0.3333 0.0009
4政党条件 政策位置 中道 5913 17640 0.3352 0.3333 0.0019
4政党条件 政策位置 右派・保守的 5757 17640 0.3264 0.3333 -0.0070
4政党条件 政策位置 左派・革新的 5970 17640 0.3384 0.3333 0.0051
4政党条件 衆議院議席数 100~199 2977 17640 0.1688 0.2000 -0.0312
4政党条件 衆議院議席数 10~49 4205 17640 0.2384 0.2000 0.0384
4政党条件 衆議院議席数 10以下 4058 17640 0.2300 0.2000 0.0300
4政党条件 衆議院議席数 200以上 2224 17640 0.1261 0.2000 -0.0739
4政党条件 衆議院議席数 50~99 4176 17640 0.2367 0.2000 0.0367
4政党条件 失業率 失業率前期比±0% 5889 17640 0.3338 0.3333 0.0005
4政党条件 失業率 失業率前期比プラス1% 5915 17640 0.3353 0.3333 0.0020
4政党条件 失業率 失業率前期比マイナス1% 5836 17640 0.3308 0.3333 -0.0025
5政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 6965 21050 0.3309 0.3333 -0.0025
5政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 6960 21050 0.3306 0.3333 -0.0027
5政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 7125 21050 0.3385 0.3333 0.0051
5政党条件 GDP成長率 GDP成長率±0% 7135 21050 0.3390 0.3333 0.0056
5政党条件 GDP成長率 GDP成長率プラス1% 6973 21050 0.3313 0.3333 -0.0021
5政党条件 GDP成長率 GDP成長率マイナス1% 6942 21050 0.3298 0.3333 -0.0035
5政党条件 与野党地位 与党 4193 21050 0.1992 0.5000 -0.3008
5政党条件 与野党地位 野党 16857 21050 0.8008 0.5000 0.3008
5政党条件 日経平均株価 日経平均前月同期比プラス1000円 6996 21050 0.3324 0.3333 -0.0010
5政党条件 日経平均株価 日経平均前月同期比マイナス1000円 6950 21050 0.3302 0.3333 -0.0032
5政党条件 日経平均株価 日経平均前月同期比変わらず 7104 21050 0.3375 0.3333 0.0041
5政党条件 政策位置 中道 7051 21050 0.3350 0.3333 0.0016
5政党条件 政策位置 右派・保守的 6963 21050 0.3308 0.3333 -0.0025
5政党条件 政策位置 左派・革新的 7036 21050 0.3343 0.3333 0.0009
5政党条件 衆議院議席数 100~199 2615 21050 0.1242 0.2000 -0.0758
5政党条件 衆議院議席数 10~49 6423 21050 0.3051 0.2000 0.1051
5政党条件 衆議院議席数 10以下 6338 21050 0.3011 0.2000 0.1011
5政党条件 衆議院議席数 200以上 2157 21050 0.1025 0.2000 -0.0975
5政党条件 衆議院議席数 50~99 3517 21050 0.1671 0.2000 -0.0329
5政党条件 失業率 失業率前期比±0% 6850 21050 0.3254 0.3333 -0.0079
5政党条件 失業率 失業率前期比プラス1% 7157 21050 0.3400 0.3333 0.0067
5政党条件 失業率 失業率前期比マイナス1% 7043 21050 0.3346 0.3333 0.0013

B.2 実験2(2026年)

図C4:回答者割付のLove plot

実験2仕様 <- study_specs$study2
実験2割付設計 <- make_balance_design(実験2仕様)
実験2SMD <- pairwise_smd_multiarm(実験2割付設計$long)
実験2最大SMD <- 実験2SMD %>%
  dplyr::group_by(variable, label) %>%
  dplyr::summarise(max_abs_smd = max(abs_smd, na.rm = TRUE), .groups = "drop")

Loveデータ <- 実験2SMD %>%
  dplyr::left_join(実験2最大SMD, by = c("variable", "label")) %>%
  dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd))

図C4 <- ggplot2::ggplot(Loveデータ, ggplot2::aes(x = abs_smd, y = 表示名)) +
  ggplot2::geom_vline(xintercept = 0.10, linetype = "dashed", linewidth = 0.55) +
  ggplot2::geom_point(alpha = 0.30, size = 1.4, position = ggplot2::position_jitter(height = 0.10, width = 0)) +
  ggplot2::geom_point(
    data = 実験2最大SMD %>% dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd)),
    ggplot2::aes(x = max_abs_smd, y = 表示名),
    inherit.aes = FALSE, shape = 21, fill = "white", size = 2.5, stroke = 0.8
  ) +
  ggplot2::labs(x = "条件間の絶対標準化平均差(|SMD|)", y = NULL,
                subtitle = "実験2(2026年):各点は条件ペア、白抜き点は最大絶対SMD") +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C4

表C5は図C4の各点に対応する。各行には比較する2条件の平均とSMDだけを残し、他条件に由来する構造的な欠損値は表示しない。

表C5 <- 実験2SMD %>%
  dplyr::transmute(
    変数 = label,
    比較 = paste0(condition_a, "政党条件-", condition_b, "政党条件"),
    `前者の平均` = round(mean_a, 3),
    `後者の平均` = round(mean_b, 3),
    `前者N` = n_a,
    `後者N` = n_b,
    SMD = round(smd, 3),
    `|SMD|` = round(abs_smd, 3)
  )
knitr::kable(表日本語(表C5), format = "html", row.names = FALSE)
変数 比較 前者の平均 後者の平均 前者N 後者N SMD |SMD|
年齢 2政党条件-3政党条件 42.000 41.814 711 1062 0.016 0.016
年齢:欠損 2政党条件-3政党条件 0.052 0.044 711 1062 0.036 0.036
4年制大学以上 2政党条件-3政党条件 0.591 0.571 711 1062 0.041 0.041
学歴:欠損 2政党条件-3政党条件 0.007 0.008 711 1062 -0.006 0.006
女性 2政党条件-3政党条件 0.308 0.298 711 1062 0.023 0.023
性別:欠損 2政党条件-3政党条件 0.010 0.011 711 1062 -0.014 0.014
世帯年収(対数) 2政党条件-3政党条件 5.956 6.018 711 1062 -0.044 0.044
支持政党:その他 2政党条件-3政党条件 0.003 0.001 711 1062 0.043 0.043
支持政党:れいわ新選組 2政党条件-3政党条件 0.013 0.021 711 1062 -0.063 0.063
支持政党:わからない 2政党条件-3政党条件 0.028 0.038 711 1062 -0.053 0.053
支持政党:チームみらい 2政党条件-3政党条件 0.059 0.047 711 1062 0.053 0.053
支持政党:中道改革連合 2政党条件-3政党条件 0.028 0.024 711 1062 0.029 0.029
支持政党:公明党 2政党条件-3政党条件 0.024 0.023 711 1062 0.009 0.009
支持政党:参政党 2政党条件-3政党条件 0.051 0.039 711 1062 0.058 0.058
支持政党:国民民主党 2政党条件-3政党条件 0.059 0.069 711 1062 -0.040 0.040
支持政党:支持政党なし 2政党条件-3政党条件 0.360 0.358 711 1062 0.005 0.005
支持政党:日本保守党 2政党条件-3政党条件 0.023 0.022 711 1062 0.006 0.006
支持政党:日本共産党 2政党条件-3政党条件 0.017 0.025 711 1062 -0.059 0.059
支持政党:日本維新の会 2政党条件-3政党条件 0.063 0.062 711 1062 0.005 0.005
支持政党:社会民主党 2政党条件-3政党条件 0.004 0.001 711 1062 0.065 0.065
支持政党:立憲民主党 2政党条件-3政党条件 0.045 0.040 711 1062 0.027 0.027
支持政党:答えたくない 2政党条件-3政党条件 0.020 0.017 711 1062 0.020 0.020
支持政党:自由民主党 2政党条件-3政党条件 0.204 0.216 711 1062 -0.029 0.029
年齢 2政党条件-4政党条件 42.000 42.459 711 1097 -0.041 0.041
年齢:欠損 2政党条件-4政党条件 0.052 0.055 711 1097 -0.012 0.012
4年制大学以上 2政党条件-4政党条件 0.591 0.599 711 1097 -0.017 0.017
学歴:欠損 2政党条件-4政党条件 0.007 0.011 711 1097 -0.041 0.041
女性 2政党条件-4政党条件 0.308 0.315 711 1097 -0.016 0.016
性別:欠損 2政党条件-4政党条件 0.010 0.004 711 1097 0.076 0.076
世帯年収(対数) 2政党条件-4政党条件 5.956 5.955 711 1097 0.001 0.001
支持政党:その他 2政党条件-4政党条件 0.003 0.003 711 1097 0.001 0.001
支持政党:れいわ新選組 2政党条件-4政党条件 0.013 0.016 711 1097 -0.031 0.031
支持政党:わからない 2政党条件-4政党条件 0.028 0.041 711 1097 -0.071 0.071
支持政党:チームみらい 2政党条件-4政党条件 0.059 0.056 711 1097 0.015 0.015
支持政党:中道改革連合 2政党条件-4政党条件 0.028 0.020 711 1097 0.053 0.053
支持政党:公明党 2政党条件-4政党条件 0.024 0.021 711 1097 0.020 0.020
支持政党:参政党 2政党条件-4政党条件 0.051 0.043 711 1097 0.037 0.037
支持政党:国民民主党 2政党条件-4政党条件 0.059 0.057 711 1097 0.011 0.011
支持政党:支持政党なし 2政党条件-4政党条件 0.360 0.356 711 1097 0.008 0.008
支持政党:日本保守党 2政党条件-4政党条件 0.023 0.027 711 1097 -0.031 0.031
支持政党:日本共産党 2政党条件-4政党条件 0.017 0.028 711 1097 -0.077 0.077
支持政党:日本維新の会 2政党条件-4政党条件 0.063 0.053 711 1097 0.045 0.045
支持政党:社会民主党 2政党条件-4政党条件 0.004 0.002 711 1097 0.044 0.044
支持政党:立憲民主党 2政党条件-4政党条件 0.045 0.040 711 1097 0.024 0.024
支持政党:答えたくない 2政党条件-4政党条件 0.020 0.014 711 1097 0.047 0.047
支持政党:自由民主党 2政党条件-4政党条件 0.204 0.223 711 1097 -0.047 0.047
年齢 2政党条件-5政党条件 42.000 42.447 711 1322 -0.039 0.039
年齢:欠損 2政党条件-5政党条件 0.052 0.047 711 1322 0.024 0.024
4年制大学以上 2政党条件-5政党条件 0.591 0.581 711 1322 0.020 0.020
学歴:欠損 2政党条件-5政党条件 0.007 0.008 711 1322 -0.015 0.015
女性 2政党条件-5政党条件 0.308 0.293 711 1322 0.033 0.033
性別:欠損 2政党条件-5政党条件 0.010 0.014 711 1322 -0.035 0.035
世帯年収(対数) 2政党条件-5政党条件 5.956 6.076 711 1322 -0.088 0.088
支持政党:その他 2政党条件-5政党条件 0.003 0.005 711 1322 -0.029 0.029
支持政党:れいわ新選組 2政党条件-5政党条件 0.013 0.016 711 1322 -0.027 0.027
支持政党:わからない 2政党条件-5政党条件 0.028 0.050 711 1322 -0.113 0.113
支持政党:チームみらい 2政党条件-5政党条件 0.059 0.057 711 1322 0.007 0.007
支持政党:中道改革連合 2政党条件-5政党条件 0.028 0.021 711 1322 0.045 0.045
支持政党:公明党 2政党条件-5政党条件 0.024 0.020 711 1322 0.029 0.029
支持政党:参政党 2政党条件-5政党条件 0.051 0.048 711 1322 0.014 0.014
支持政党:国民民主党 2政党条件-5政党条件 0.059 0.057 711 1322 0.007 0.007
支持政党:支持政党なし 2政党条件-5政党条件 0.360 0.328 711 1322 0.067 0.067
支持政党:日本保守党 2政党条件-5政党条件 0.023 0.030 711 1322 -0.048 0.048
支持政党:日本共産党 2政党条件-5政党条件 0.017 0.025 711 1322 -0.056 0.056
支持政党:日本維新の会 2政党条件-5政党条件 0.063 0.051 711 1322 0.054 0.054
支持政党:社会民主党 2政党条件-5政党条件 0.004 0.002 711 1322 0.034 0.034
支持政党:立憲民主党 2政党条件-5政党条件 0.045 0.045 711 1322 0.002 0.002
支持政党:答えたくない 2政党条件-5政党条件 0.020 0.024 711 1322 -0.031 0.031
支持政党:自由民主党 2政党条件-5政党条件 0.204 0.221 711 1322 -0.041 0.041
年齢 3政党条件-4政党条件 41.814 42.459 1062 1097 -0.057 0.057
年齢:欠損 3政党条件-4政党条件 0.044 0.055 1062 1097 -0.048 0.048
4年制大学以上 3政党条件-4政党条件 0.571 0.599 1062 1097 -0.057 0.057
学歴:欠損 3政党条件-4政党条件 0.008 0.011 1062 1097 -0.036 0.036
女性 3政党条件-4政党条件 0.298 0.315 1062 1097 -0.039 0.039
性別:欠損 3政党条件-4政党条件 0.011 0.004 1062 1097 0.089 0.089
世帯年収(対数) 3政党条件-4政党条件 6.018 5.955 1062 1097 0.044 0.044
支持政党:その他 3政党条件-4政党条件 0.001 0.003 1062 1097 -0.042 0.042
支持政党:れいわ新選組 3政党条件-4政党条件 0.021 0.016 1062 1097 0.032 0.032
支持政党:わからない 3政党条件-4政党条件 0.038 0.041 1062 1097 -0.017 0.017
支持政党:チームみらい 3政党条件-4政党条件 0.047 0.056 1062 1097 -0.039 0.039
支持政党:中道改革連合 3政党条件-4政党条件 0.024 0.020 1062 1097 0.024 0.024
支持政党:公明党 3政党条件-4政党条件 0.023 0.021 1062 1097 0.011 0.011
支持政党:参政党 3政党条件-4政党条件 0.039 0.043 1062 1097 -0.021 0.021
支持政党:国民民主党 3政党条件-4政党条件 0.069 0.057 1062 1097 0.050 0.050
支持政党:支持政党なし 3政党条件-4政党条件 0.358 0.356 1062 1097 0.003 0.003
支持政党:日本保守党 3政党条件-4政党条件 0.022 0.027 1062 1097 -0.037 0.037
支持政党:日本共産党 3政党条件-4政党条件 0.025 0.028 1062 1097 -0.018 0.018
支持政党:日本維新の会 3政党条件-4政党条件 0.062 0.053 1062 1097 0.040 0.040
支持政党:社会民主党 3政党条件-4政党条件 0.001 0.002 1062 1097 -0.024 0.024
支持政党:立憲民主党 3政党条件-4政党条件 0.040 0.040 1062 1097 -0.003 0.003
支持政党:答えたくない 3政党条件-4政党条件 0.017 0.014 1062 1097 0.027 0.027
支持政党:自由民主党 3政党条件-4政党条件 0.216 0.223 1062 1097 -0.019 0.019
年齢 3政党条件-5政党条件 41.814 42.447 1062 1322 -0.055 0.055
年齢:欠損 3政党条件-5政党条件 0.044 0.047 1062 1322 -0.013 0.013
4年制大学以上 3政党条件-5政党条件 0.571 0.581 1062 1322 -0.021 0.021
学歴:欠損 3政党条件-5政党条件 0.008 0.008 1062 1322 -0.009 0.009
女性 3政党条件-5政党条件 0.298 0.293 1062 1322 0.011 0.011
性別:欠損 3政党条件-5政党条件 0.011 0.014 1062 1322 -0.021 0.021
世帯年収(対数) 3政党条件-5政党条件 6.018 6.076 1062 1322 -0.045 0.045
支持政党:その他 3政党条件-5政党条件 0.001 0.005 1062 1322 -0.069 0.069
支持政党:れいわ新選組 3政党条件-5政党条件 0.021 0.016 1062 1322 0.036 0.036
支持政党:わからない 3政党条件-5政党条件 0.038 0.050 1062 1322 -0.060 0.060
支持政党:チームみらい 3政党条件-5政党条件 0.047 0.057 1062 1322 -0.047 0.047
支持政党:中道改革連合 3政党条件-5政党条件 0.024 0.021 1062 1322 0.016 0.016
支持政党:公明党 3政党条件-5政党条件 0.023 0.020 1062 1322 0.020 0.020
支持政党:参政党 3政党条件-5政党条件 0.039 0.048 1062 1322 -0.045 0.045
支持政党:国民民主党 3政党条件-5政党条件 0.069 0.057 1062 1322 0.046 0.046
支持政党:支持政党なし 3政党条件-5政党条件 0.358 0.328 1062 1322 0.062 0.062
支持政党:日本保守党 3政党条件-5政党条件 0.022 0.030 1062 1322 -0.054 0.054
支持政党:日本共産党 3政党条件-5政党条件 0.025 0.025 1062 1322 0.003 0.003
支持政党:日本維新の会 3政党条件-5政党条件 0.062 0.051 1062 1322 0.050 0.050
支持政党:社会民主党 3政党条件-5政党条件 0.001 0.002 1062 1322 -0.033 0.033
支持政党:立憲民主党 3政党条件-5政党条件 0.040 0.045 1062 1322 -0.025 0.025
支持政党:答えたくない 3政党条件-5政党条件 0.017 0.024 1062 1322 -0.051 0.051
支持政党:自由民主党 3政党条件-5政党条件 0.216 0.221 1062 1322 -0.013 0.013
年齢 4政党条件-5政党条件 42.459 42.447 1097 1322 0.001 0.001
年齢:欠損 4政党条件-5政党条件 0.055 0.047 1097 1322 0.035 0.035
4年制大学以上 4政党条件-5政党条件 0.599 0.581 1097 1322 0.037 0.037
学歴:欠損 4政党条件-5政党条件 0.011 0.008 1097 1322 0.027 0.027
女性 4政党条件-5政党条件 0.315 0.293 1097 1322 0.049 0.049
性別:欠損 4政党条件-5政党条件 0.004 0.014 1097 1322 -0.108 0.108
世帯年収(対数) 4政党条件-5政党条件 5.955 6.076 1097 1322 -0.086 0.086
支持政党:その他 4政党条件-5政党条件 0.003 0.005 1097 1322 -0.030 0.030
支持政党:れいわ新選組 4政党条件-5政党条件 0.016 0.016 1097 1322 0.004 0.004
支持政党:わからない 4政党条件-5政党条件 0.041 0.050 1097 1322 -0.043 0.043
支持政党:チームみらい 4政党条件-5政党条件 0.056 0.057 1097 1322 -0.008 0.008
支持政党:中道改革連合 4政党条件-5政党条件 0.020 0.021 1097 1322 -0.008 0.008
支持政党:公明党 4政党条件-5政党条件 0.021 0.020 1097 1322 0.009 0.009
支持政党:参政党 4政党条件-5政党条件 0.043 0.048 1097 1322 -0.023 0.023
支持政党:国民民主党 4政党条件-5政党条件 0.057 0.057 1097 1322 -0.004 0.004
支持政党:支持政党なし 4政党条件-5政党条件 0.356 0.328 1097 1322 0.059 0.059
支持政党:日本保守党 4政党条件-5政党条件 0.027 0.030 1097 1322 -0.017 0.017
支持政党:日本共産党 4政党条件-5政党条件 0.028 0.025 1097 1322 0.020 0.020
支持政党:日本維新の会 4政党条件-5政党条件 0.053 0.051 1097 1322 0.010 0.010
支持政党:社会民主党 4政党条件-5政党条件 0.002 0.002 1097 1322 -0.010 0.010
支持政党:立憲民主党 4政党条件-5政党条件 0.040 0.045 1097 1322 -0.022 0.022
支持政党:答えたくない 4政党条件-5政党条件 0.014 0.024 1097 1322 -0.077 0.077
支持政党:自由民主党 4政党条件-5政党条件 0.223 0.221 1097 1322 0.006 0.006

図C5:条件平均の45度線診断

図C5は図C4と同じ回答者レベルの割付バランスを、各共変量の条件平均を標準化したうえで2条件ずつ45度線と比較したものである。

対角線データ <- assignment_balance_results$study2$diagonal_data %>%
  dplyr::mutate(
    比較 = paste0(condition_a, "政党条件-", condition_b, "政党条件")
  )

ラベル対象 <- 対角線データ %>%
  dplyr::group_by(比較) %>%
  dplyr::slice_max(abs_diagonal_deviation, n = 3, with_ties = FALSE) %>%
  dplyr::ungroup()

軸範囲 <- max(abs(c(対角線データ$x_mean, 対角線データ$y_mean)), na.rm = TRUE)
軸範囲 <- max(0.10, 軸範囲 * 1.15)

図C5 <- ggplot2::ggplot(対角線データ, ggplot2::aes(x = x_mean, y = y_mean)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.60) +
  ggplot2::geom_hline(yintercept = 0, linewidth = 0.25) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.25) +
  ggplot2::geom_point(shape = 21, fill = "white", size = 2.2) +
  ggplot2::geom_text(data = ラベル対象, ggplot2::aes(label = label), size = 2.6, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 比較, ncol = 3) +
  ggplot2::coord_equal(xlim = c(-軸範囲, 軸範囲), ylim = c(-軸範囲, 軸範囲)) +
  ggplot2::labs(x = "左側条件の標準化共変量平均", y = "右側条件の標準化共変量平均") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C5

表C6 <- assignment_balance_results$study2$summary %>%
  dplyr::transmute(
    変数 = label,
    `2政党条件の平均` = round(mean_condition_2, 3),
    `3政党条件の平均` = round(mean_condition_3, 3),
    `4政党条件の平均` = round(mean_condition_4, 3),
    `5政党条件の平均` = round(mean_condition_5, 3),
    `最大|SMD|` = round(max_abs_smd, 3),
    `Holm補正p値` = signif(p_holm, 3)
  )
knitr::kable(表日本語(表C6), format = "html", row.names = FALSE)
変数 2政党条件の平均 3政党条件の平均 4政党条件の平均 5政党条件の平均 最大|SMD| Holm補正p値
支持政党:わからない 0.028 0.038 0.041 0.050 0.113 1
性別:欠損 0.010 0.011 0.004 0.014 0.108 1
世帯年収(対数) 5.956 6.018 5.955 6.076 0.088 1
支持政党:答えたくない 0.020 0.017 0.014 0.024 0.077 1
支持政党:日本共産党 0.017 0.025 0.028 0.025 0.077 1
支持政党:その他 0.003 0.001 0.003 0.005 0.069 1
支持政党:支持政党なし 0.360 0.358 0.356 0.328 0.067 1
支持政党:社会民主党 0.004 0.001 0.002 0.002 0.065 1
支持政党:れいわ新選組 0.013 0.021 0.016 0.016 0.063 1
支持政党:参政党 0.051 0.039 0.043 0.048 0.058 1
4年制大学以上 0.591 0.571 0.599 0.581 0.057 1
年齢 42.000 41.814 42.459 42.447 0.057 1
支持政党:日本維新の会 0.063 0.062 0.053 0.051 0.054 1
支持政党:日本保守党 0.023 0.022 0.027 0.030 0.054 1
支持政党:チームみらい 0.059 0.047 0.056 0.057 0.053 1
支持政党:中道改革連合 0.028 0.024 0.020 0.021 0.053 1
支持政党:国民民主党 0.059 0.069 0.057 0.057 0.050 1
女性 0.308 0.298 0.315 0.293 0.049 1
年齢:欠損 0.052 0.044 0.055 0.047 0.048 1
支持政党:自由民主党 0.204 0.216 0.223 0.221 0.047 1
学歴:欠損 0.007 0.008 0.011 0.008 0.041 1
支持政党:公明党 0.024 0.023 0.021 0.020 0.029 1
支持政党:立憲民主党 0.045 0.040 0.040 0.045 0.027 1

図C6:プロフィール属性水準の無作為提示

図C6以降は回答者の条件割付ではなく、各コンジョイント課題内で属性水準が設計どおり一様に提示されているかを確認するものである。

属性頻度 <- profile_randomization_results$study2$frequency %>%
  dplyr::mutate(
    属性 = 属性日本語(attribute),
    条件 = 条件日本語(party_n, "study2")
  )

表示ラベル <- 属性頻度 %>%
  dplyr::group_by(属性, 条件) %>%
  dplyr::slice_max(abs_deviation, n = 2, with_ties = FALSE) %>%
  dplyr::ungroup()

図C6 <- ggplot2::ggplot(属性頻度, ggplot2::aes(x = expected_share, y = observed_share, shape = 条件)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.65) +
  ggplot2::geom_point(size = 2.2, fill = "white") +
  ggplot2::geom_text(data = 表示ラベル, ggplot2::aes(label = level), size = 2.4, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 属性, ncol = 3) +
  ggplot2::coord_equal() +
  ggplot2::labs(x = "設計上の期待比率", y = "観測比率", shape = "条件") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank(), legend.position = "bottom")
図C6

表C7 <- profile_randomization_results$study2$uniformity_tests %>%
  dplyr::transmute(
    条件 = 条件日本語(party_n, "study2"),
    属性 = 属性日本語(attribute),
    `カイ二乗値` = round(chi_square, 3),
    自由度 = df,
    p値 = signif(p_value, 3),
    `Holm補正p値` = signif(p_holm, 3),
    `最大絶対比率差` = round(max_abs_share_deviation, 4)
  )
knitr::kable(表日本語(表C7), format = "html", row.names = FALSE)
条件 属性 カイ二乗値 自由度 p値 Holm補正p値 最大絶対比率差
2政党条件 消費者物価指数(CPI) 1.667 2 0.43500 1.000 0.0070
2政党条件 GDP成長率 0.740 2 0.69100 1.000 0.0044
2政党条件 与野党地位 2.601 1 0.10700 1.000 0.0096
2政党条件 日経平均株価 9.289 2 0.00961 0.260 0.0158
2政党条件 政策位置 2.624 2 0.26900 1.000 0.0089
2政党条件 衆議院議席数 9.259 4 0.05490 1.000 0.0100
2政党条件 失業率 0.276 2 0.87100 1.000 0.0027
3政党条件 消費者物価指数(CPI) 0.285 2 0.86700 1.000 0.0018
3政党条件 GDP成長率 3.260 2 0.19600 1.000 0.0063
3政党条件 与野党地位 0.081 1 0.77500 1.000 0.0011
3政党条件 日経平均株価 0.390 2 0.82300 1.000 0.0023
3政党条件 政策位置 1.996 2 0.36900 1.000 0.0051
3政党条件 衆議院議席数 2.861 4 0.58100 1.000 0.0038
3政党条件 失業率 2.895 2 0.23500 1.000 0.0062
4政党条件 消費者物価指数(CPI) 1.732 2 0.42100 1.000 0.0041
4政党条件 GDP成長率 0.239 2 0.88700 1.000 0.0015
4政党条件 与野党地位 0.164 1 0.68500 1.000 0.0014
4政党条件 日経平均株価 9.409 2 0.00906 0.254 0.0097
4政党条件 政策位置 1.147 2 0.56400 1.000 0.0033
4政党条件 衆議院議席数 2.153 4 0.70800 1.000 0.0038
4政党条件 失業率 2.351 2 0.30900 1.000 0.0045
5政党条件 消費者物価指数(CPI) 0.564 2 0.75400 1.000 0.0018
5政党条件 GDP成長率 0.215 2 0.89800 1.000 0.0012
5政党条件 与野党地位 0.327 1 0.56700 1.000 0.0016
5政党条件 日経平均株価 2.328 2 0.31200 1.000 0.0039
5政党条件 政策位置 1.792 2 0.40800 1.000 0.0034
5政党条件 衆議院議席数 1.764 4 0.77900 1.000 0.0026
5政党条件 失業率 4.171 2 0.12400 1.000 0.0053
表C8 <- 属性頻度 %>%
  dplyr::transmute(
    条件,
    属性,
    水準 = level,
    観測数 = observed_n,
    総数 = total_n,
    観測比率 = round(observed_share, 4),
    期待比率 = round(expected_share, 4),
= round(deviation, 4)
  )
knitr::kable(表日本語(表C8), format = "html", row.names = FALSE)
条件 属性 水準 観測数 総数 観測比率 期待比率
2政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 2335 7110 0.3284 0.3333 -0.0049
2政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 2355 7110 0.3312 0.3333 -0.0021
2政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 2420 7110 0.3404 0.3333 0.0070
2政党条件 GDP成長率 GDP成長率±0% 2342 7110 0.3294 0.3333 -0.0039
2政党条件 GDP成長率 GDP成長率プラス1% 2401 7110 0.3377 0.3333 0.0044
2政党条件 GDP成長率 GDP成長率マイナス1% 2367 7110 0.3329 0.3333 -0.0004
2政党条件 与野党地位 与党 3623 7110 0.5096 0.5000 0.0096
2政党条件 与野党地位 野党 3487 7110 0.4904 0.5000 -0.0096
2政党条件 日経平均株価 日経平均前月同期比プラス1000円 2354 7110 0.3311 0.3333 -0.0023
2政党条件 日経平均株価 日経平均前月同期比マイナス1000円 2274 7110 0.3198 0.3333 -0.0135
2政党条件 日経平均株価 日経平均前月同期比変わらず 2482 7110 0.3491 0.3333 0.0158
2政党条件 政策位置 中道 2413 7110 0.3394 0.3333 0.0060
2政党条件 政策位置 右派・保守的 2390 7110 0.3361 0.3333 0.0028
2政党条件 政策位置 左派・革新的 2307 7110 0.3245 0.3333 -0.0089
2政党条件 衆議院議席数 100~199 1400 7110 0.1969 0.2000 -0.0031
2政党条件 衆議院議席数 10~49 1351 7110 0.1900 0.2000 -0.0100
2政党条件 衆議院議席数 10以下 1491 7110 0.2097 0.2000 0.0097
2政党条件 衆議院議席数 200以上 1398 7110 0.1966 0.2000 -0.0034
2政党条件 衆議院議席数 50~99 1470 7110 0.2068 0.2000 0.0068
2政党条件 失業率 失業率前期比±0% 2389 7110 0.3360 0.3333 0.0027
2政党条件 失業率 失業率前期比プラス1% 2353 7110 0.3309 0.3333 -0.0024
2政党条件 失業率 失業率前期比マイナス1% 2368 7110 0.3331 0.3333 -0.0003
3政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 5282 15930 0.3316 0.3333 -0.0018
3政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 5311 15930 0.3334 0.3333 0.0001
3政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 5337 15930 0.3350 0.3333 0.0017
3政党条件 GDP成長率 GDP成長率±0% 5394 15930 0.3386 0.3333 0.0053
3政党条件 GDP成長率 GDP成長率プラス1% 5210 15930 0.3271 0.3333 -0.0063
3政党条件 GDP成長率 GDP成長率マイナス1% 5326 15930 0.3343 0.3333 0.0010
3政党条件 与野党地位 与党 7947 15930 0.4989 0.5000 -0.0011
3政党条件 与野党地位 野党 7983 15930 0.5011 0.5000 0.0011
3政党条件 日経平均株価 日経平均前月同期比プラス1000円 5336 15930 0.3350 0.3333 0.0016
3政党条件 日経平均株価 日経平均前月同期比マイナス1000円 5320 15930 0.3340 0.3333 0.0006
3政党条件 日経平均株価 日経平均前月同期比変わらず 5274 15930 0.3311 0.3333 -0.0023
3政党条件 政策位置 中道 5392 15930 0.3385 0.3333 0.0051
3政党条件 政策位置 右派・保守的 5285 15930 0.3318 0.3333 -0.0016
3政党条件 政策位置 左派・革新的 5253 15930 0.3298 0.3333 -0.0036
3政党条件 衆議院議席数 100~199 3246 15930 0.2038 0.2000 0.0038
3政党条件 衆議院議席数 10~49 3149 15930 0.1977 0.2000 -0.0023
3政党条件 衆議院議席数 10以下 3201 15930 0.2009 0.2000 0.0009
3政党条件 衆議院議席数 200以上 3207 15930 0.2013 0.2000 0.0013
3政党条件 衆議院議席数 50~99 3127 15930 0.1963 0.2000 -0.0037
3政党条件 失業率 失業率前期比±0% 5212 15930 0.3272 0.3333 -0.0062
3政党条件 失業率 失業率前期比プラス1% 5381 15930 0.3378 0.3333 0.0045
3政党条件 失業率 失業率前期比マイナス1% 5337 15930 0.3350 0.3333 0.0017
4政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 7255 21940 0.3307 0.3333 -0.0027
4政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 7404 21940 0.3375 0.3333 0.0041
4政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 7281 21940 0.3319 0.3333 -0.0015
4政党条件 GDP成長率 GDP成長率±0% 7281 21940 0.3319 0.3333 -0.0015
4政党条件 GDP成長率 GDP成長率プラス1% 7339 21940 0.3345 0.3333 0.0012
4政党条件 GDP成長率 GDP成長率マイナス1% 7320 21940 0.3336 0.3333 0.0003
4政党条件 与野党地位 与党 11000 21940 0.5014 0.5000 0.0014
4政党条件 与野党地位 野党 10940 21940 0.4986 0.5000 -0.0014
4政党条件 日経平均株価 日経平均前月同期比プラス1000円 7229 21940 0.3295 0.3333 -0.0038
4政党条件 日経平均株価 日経平均前月同期比マイナス1000円 7185 21940 0.3275 0.3333 -0.0058
4政党条件 日経平均株価 日経平均前月同期比変わらず 7526 21940 0.3430 0.3333 0.0097
4政党条件 政策位置 中道 7296 21940 0.3325 0.3333 -0.0008
4政党条件 政策位置 右派・保守的 7259 21940 0.3309 0.3333 -0.0025
4政党条件 政策位置 左派・革新的 7385 21940 0.3366 0.3333 0.0033
4政党条件 衆議院議席数 100~199 4471 21940 0.2038 0.2000 0.0038
4政党条件 衆議院議席数 10~49 4371 21940 0.1992 0.2000 -0.0008
4政党条件 衆議院議席数 10以下 4389 21940 0.2000 0.2000 0.0000
4政党条件 衆議院議席数 200以上 4358 21940 0.1986 0.2000 -0.0014
4政党条件 衆議院議席数 50~99 4351 21940 0.1983 0.2000 -0.0017
4政党条件 失業率 失業率前期比±0% 7412 21940 0.3378 0.3333 0.0045
4政党条件 失業率 失業率前期比プラス1% 7228 21940 0.3294 0.3333 -0.0039
4政党条件 失業率 失業率前期比マイナス1% 7300 21940 0.3327 0.3333 -0.0006
5政党条件 消費者物価指数(CPI) CPI前期比±0ポイント 11075 33050 0.3351 0.3333 0.0018
5政党条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 11011 33050 0.3332 0.3333 -0.0002
5政党条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 10964 33050 0.3317 0.3333 -0.0016
5政党条件 GDP成長率 GDP成長率±0% 11038 33050 0.3340 0.3333 0.0006
5政党条件 GDP成長率 GDP成長率プラス1% 10977 33050 0.3321 0.3333 -0.0012
5政党条件 GDP成長率 GDP成長率マイナス1% 11035 33050 0.3339 0.3333 0.0006
5政党条件 与野党地位 与党 16473 33050 0.4984 0.5000 -0.0016
5政党条件 与野党地位 野党 16577 33050 0.5016 0.5000 0.0016
5政党条件 日経平均株価 日経平均前月同期比プラス1000円 11056 33050 0.3345 0.3333 0.0012
5政党条件 日経平均株価 日経平均前月同期比マイナス1000円 11105 33050 0.3360 0.3333 0.0027
5政党条件 日経平均株価 日経平均前月同期比変わらず 10889 33050 0.3295 0.3333 -0.0039
5政党条件 政策位置 中道 10985 33050 0.3324 0.3333 -0.0010
5政党条件 政策位置 右派・保守的 11128 33050 0.3367 0.3333 0.0034
5政党条件 政策位置 左派・革新的 10937 33050 0.3309 0.3333 -0.0024
5政党条件 衆議院議席数 100~199 6589 33050 0.1994 0.2000 -0.0006
5政党条件 衆議院議席数 10~49 6697 33050 0.2026 0.2000 0.0026
5政党条件 衆議院議席数 10以下 6550 33050 0.1982 0.2000 -0.0018
5政党条件 衆議院議席数 200以上 6611 33050 0.2000 0.2000 0.0000
5政党条件 衆議院議席数 50~99 6603 33050 0.1998 0.2000 -0.0002
5政党条件 失業率 失業率前期比±0% 11191 33050 0.3386 0.3333 0.0053
5政党条件 失業率 失業率前期比プラス1% 10916 33050 0.3303 0.3333 -0.0030
5政党条件 失業率 失業率前期比マイナス1% 10943 33050 0.3311 0.3333 -0.0022

B.3 実験3(2026年)

図C7:回答者割付のLove plot

実験3仕様 <- study_specs$study3
実験3割付設計 <- make_balance_design(実験3仕様)
実験3SMD <- pairwise_smd_multiarm(実験3割付設計$long)
実験3最大SMD <- 実験3SMD %>%
  dplyr::group_by(variable, label) %>%
  dplyr::summarise(max_abs_smd = max(abs_smd, na.rm = TRUE), .groups = "drop")

Loveデータ <- 実験3SMD %>%
  dplyr::left_join(実験3最大SMD, by = c("variable", "label")) %>%
  dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd))

図C7 <- ggplot2::ggplot(Loveデータ, ggplot2::aes(x = abs_smd, y = 表示名)) +
  ggplot2::geom_vline(xintercept = 0.10, linetype = "dashed", linewidth = 0.55) +
  ggplot2::geom_point(alpha = 0.30, size = 1.4, position = ggplot2::position_jitter(height = 0.10, width = 0)) +
  ggplot2::geom_point(
    data = 実験3最大SMD %>% dplyr::mutate(表示名 = stats::reorder(label, max_abs_smd)),
    ggplot2::aes(x = max_abs_smd, y = 表示名),
    inherit.aes = FALSE, shape = 21, fill = "white", size = 2.5, stroke = 0.8
  ) +
  ggplot2::labs(x = "条件間の絶対標準化平均差(|SMD|)", y = NULL,
                subtitle = "実験3(2026年):各点は条件ペア、白抜き点は最大絶対SMD") +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C7

表C9は図C7の各点に対応する。

表C9 <- 実験3SMD %>%
  dplyr::transmute(
    変数 = label,
    比較 = paste0(condition_a, "選択肢条件-", condition_b, "選択肢条件"),
    `前者の平均` = round(mean_a, 3),
    `後者の平均` = round(mean_b, 3),
    `前者N` = n_a,
    `後者N` = n_b,
    SMD = round(smd, 3),
    `|SMD|` = round(abs_smd, 3)
  )
knitr::kable(表日本語(表C9), format = "html", row.names = FALSE)
変数 比較 前者の平均 後者の平均 前者N 後者N SMD |SMD|
年齢 2選択肢条件-3選択肢条件 41.246 42.353 716 939 -0.097 0.097
年齢:欠損 2選択肢条件-3選択肢条件 0.052 0.052 716 939 -0.002 0.002
4年制大学以上 2選択肢条件-3選択肢条件 0.609 0.600 716 939 0.019 0.019
学歴:欠損 2選択肢条件-3選択肢条件 0.007 0.009 716 939 -0.018 0.018
女性 2選択肢条件-3選択肢条件 0.246 0.298 716 939 -0.118 0.118
性別:欠損 2選択肢条件-3選択肢条件 0.020 0.012 716 939 0.063 0.063
世帯年収(対数) 2選択肢条件-3選択肢条件 5.919 6.034 716 939 -0.079 0.079
支持政党:その他 2選択肢条件-3選択肢条件 0.003 0.002 716 939 0.013 0.013
支持政党:れいわ新選組 2選択肢条件-3選択肢条件 0.015 0.013 716 939 0.022 0.022
支持政党:わからない 2選択肢条件-3選択肢条件 0.038 0.049 716 939 -0.055 0.055
支持政党:チームみらい 2選択肢条件-3選択肢条件 0.042 0.040 716 939 0.007 0.007
支持政党:中道改革連合 2選択肢条件-3選択肢条件 0.032 0.024 716 939 0.046 0.046
支持政党:公明党 2選択肢条件-3選択肢条件 0.011 0.011 716 939 0.005 0.005
支持政党:参政党 2選択肢条件-3選択肢条件 0.042 0.049 716 939 -0.034 0.034
支持政党:国民民主党 2選択肢条件-3選択肢条件 0.068 0.081 716 939 -0.048 0.048
支持政党:支持政党なし 2選択肢条件-3選択肢条件 0.365 0.357 716 939 0.016 0.016
支持政党:日本保守党 2選択肢条件-3選択肢条件 0.025 0.015 716 939 0.073 0.073
支持政党:日本共産党 2選択肢条件-3選択肢条件 0.022 0.014 716 939 0.064 0.064
支持政党:日本維新の会 2選択肢条件-3選択肢条件 0.053 0.049 716 939 0.019 0.019
支持政党:社会民主党 2選択肢条件-3選択肢条件 0.003 0.003 716 939 -0.007 0.007
支持政党:立憲民主党 2選択肢条件-3選択肢条件 0.036 0.040 716 939 -0.022 0.022
支持政党:答えたくない 2選択肢条件-3選択肢条件 0.017 0.019 716 939 -0.018 0.018
支持政党:自由民主党 2選択肢条件-3選択肢条件 0.228 0.233 716 939 -0.013 0.013
地域:17 2選択肢条件-3選択肢条件 0.145 0.153 716 939 -0.023 0.023
地域:27 2選択肢条件-3選択肢条件 0.214 0.201 716 939 0.031 0.031
地域:35 2選択肢条件-3選択肢条件 0.085 0.085 716 939 0.000 0.000
地域:45 2選択肢条件-3選択肢条件 0.087 0.081 716 939 0.020 0.020
地域:9 2選択肢条件-3選択肢条件 0.383 0.396 716 939 -0.028 0.028
左右自己位置づけ 2選択肢条件-3選択肢条件 5.430 5.384 716 939 0.025 0.025
左右自己位置づけ:欠損 2選択肢条件-3選択肢条件 0.080 0.096 716 939 -0.057 0.057
年齢 2選択肢条件-4選択肢条件 41.246 42.935 716 1063 -0.145 0.145
年齢:欠損 2選択肢条件-4選択肢条件 0.052 0.047 716 1063 0.021 0.021
4年制大学以上 2選択肢条件-4選択肢条件 0.609 0.583 716 1063 0.052 0.052
学歴:欠損 2選択肢条件-4選択肢条件 0.007 0.008 716 1063 -0.006 0.006
女性 2選択肢条件-4選択肢条件 0.246 0.285 716 1063 -0.089 0.089
性別:欠損 2選択肢条件-4選択肢条件 0.020 0.014 716 1063 0.042 0.042
世帯年収(対数) 2選択肢条件-4選択肢条件 5.919 5.964 716 1063 -0.030 0.030
支持政党:その他 2選択肢条件-4選択肢条件 0.003 0.001 716 1063 0.043 0.043
支持政党:れいわ新選組 2選択肢条件-4選択肢条件 0.015 0.014 716 1063 0.010 0.010
支持政党:わからない 2選択肢条件-4選択肢条件 0.038 0.040 716 1063 -0.014 0.014
支持政党:チームみらい 2選択肢条件-4選択肢条件 0.042 0.048 716 1063 -0.029 0.029
支持政党:中道改革連合 2選択肢条件-4選択肢条件 0.032 0.032 716 1063 0.001 0.001
支持政党:公明党 2選択肢条件-4選択肢条件 0.011 0.009 716 1063 0.017 0.017
支持政党:参政党 2選択肢条件-4選択肢条件 0.042 0.040 716 1063 0.012 0.012
支持政党:国民民主党 2選択肢条件-4選択肢条件 0.068 0.066 716 1063 0.010 0.010
支持政党:支持政党なし 2選択肢条件-4選択肢条件 0.365 0.348 716 1063 0.034 0.034
支持政党:日本保守党 2選択肢条件-4選択肢条件 0.025 0.024 716 1063 0.011 0.011
支持政党:日本共産党 2選択肢条件-4選択肢条件 0.022 0.021 716 1063 0.011 0.011
支持政党:日本維新の会 2選択肢条件-4選択肢条件 0.053 0.060 716 1063 -0.031 0.031
支持政党:社会民主党 2選択肢条件-4選択肢条件 0.003 0.004 716 1063 -0.017 0.017
支持政党:立憲民主党 2選択肢条件-4選択肢条件 0.036 0.035 716 1063 0.008 0.008
支持政党:答えたくない 2選択肢条件-4選択肢条件 0.017 0.020 716 1063 -0.022 0.022
支持政党:自由民主党 2選択肢条件-4選択肢条件 0.228 0.239 716 1063 -0.027 0.027
地域:17 2選択肢条件-4選択肢条件 0.145 0.165 716 1063 -0.054 0.054
地域:27 2選択肢条件-4選択肢条件 0.214 0.200 716 1063 0.033 0.033
地域:35 2選択肢条件-4選択肢条件 0.085 0.092 716 1063 -0.025 0.025
地域:45 2選択肢条件-4選択肢条件 0.087 0.073 716 1063 0.049 0.049
地域:9 2選択肢条件-4選択肢条件 0.383 0.365 716 1063 0.037 0.037
左右自己位置づけ 2選択肢条件-4選択肢条件 5.430 5.373 716 1063 0.031 0.031
左右自己位置づけ:欠損 2選択肢条件-4選択肢条件 0.080 0.076 716 1063 0.013 0.013
年齢 2選択肢条件-5選択肢条件 41.246 43.582 716 1314 -0.203 0.203
年齢:欠損 2選択肢条件-5選択肢条件 0.052 0.042 716 1314 0.046 0.046
4年制大学以上 2選択肢条件-5選択肢条件 0.609 0.561 716 1314 0.098 0.098
学歴:欠損 2選択肢条件-5選択肢条件 0.007 0.010 716 1314 -0.032 0.032
女性 2選択肢条件-5選択肢条件 0.246 0.271 716 1314 -0.057 0.057
性別:欠損 2選択肢条件-5選択肢条件 0.020 0.015 716 1314 0.033 0.033
世帯年収(対数) 2選択肢条件-5選択肢条件 5.919 5.990 716 1314 -0.050 0.050
支持政党:その他 2選択肢条件-5選択肢条件 0.003 0.003 716 1314 -0.005 0.005
支持政党:れいわ新選組 2選択肢条件-5選択肢条件 0.015 0.018 716 1314 -0.023 0.023
支持政党:わからない 2選択肢条件-5選択肢条件 0.038 0.036 716 1314 0.010 0.010
支持政党:チームみらい 2選択肢条件-5選択肢条件 0.042 0.051 716 1314 -0.043 0.043
支持政党:中道改革連合 2選択肢条件-5選択肢条件 0.032 0.030 716 1314 0.010 0.010
支持政党:公明党 2選択肢条件-5選択肢条件 0.011 0.012 716 1314 -0.009 0.009
支持政党:参政党 2選択肢条件-5選択肢条件 0.042 0.040 716 1314 0.012 0.012
支持政党:国民民主党 2選択肢条件-5選択肢条件 0.068 0.069 716 1314 -0.003 0.003
支持政党:支持政党なし 2選択肢条件-5選択肢条件 0.365 0.340 716 1314 0.051 0.051
支持政党:日本保守党 2選択肢条件-5選択肢条件 0.025 0.024 716 1314 0.005 0.005
支持政党:日本共産党 2選択肢条件-5選択肢条件 0.022 0.021 716 1314 0.012 0.012
支持政党:日本維新の会 2選択肢条件-5選択肢条件 0.053 0.046 716 1314 0.034 0.034
支持政党:社会民主党 2選択肢条件-5選択肢条件 0.003 0.005 716 1314 -0.029 0.029
支持政党:立憲民主党 2選択肢条件-5選択肢条件 0.036 0.048 716 1314 -0.058 0.058
支持政党:答えたくない 2選択肢条件-5選択肢条件 0.017 0.021 716 1314 -0.028 0.028
支持政党:自由民主党 2選択肢条件-5選択肢条件 0.228 0.237 716 1314 -0.021 0.021
地域:17 2選択肢条件-5選択肢条件 0.145 0.170 716 1314 -0.067 0.067
地域:27 2選択肢条件-5選択肢条件 0.214 0.196 716 1314 0.043 0.043
地域:35 2選択肢条件-5選択肢条件 0.085 0.074 716 1314 0.042 0.042
地域:45 2選択肢条件-5選択肢条件 0.087 0.091 716 1314 -0.014 0.014
地域:9 2選択肢条件-5選択肢条件 0.383 0.364 716 1314 0.039 0.039
左右自己位置づけ 2選択肢条件-5選択肢条件 5.430 5.414 716 1314 0.009 0.009
左右自己位置づけ:欠損 2選択肢条件-5選択肢条件 0.080 0.088 716 1314 -0.029 0.029
年齢 3選択肢条件-4選択肢条件 42.353 42.935 939 1063 -0.051 0.051
年齢:欠損 3選択肢条件-4選択肢条件 0.052 0.047 939 1063 0.024 0.024
4年制大学以上 3選択肢条件-4選択肢条件 0.600 0.583 939 1063 0.033 0.033
学歴:欠損 3選択肢条件-4選択肢条件 0.009 0.008 939 1063 0.011 0.011
女性 3選択肢条件-4選択肢条件 0.298 0.285 939 1063 0.029 0.029
性別:欠損 3選択肢条件-4選択肢条件 0.012 0.014 939 1063 -0.021 0.021
世帯年収(対数) 3選択肢条件-4選択肢条件 6.034 5.964 939 1063 0.049 0.049
支持政党:その他 3選択肢条件-4選択肢条件 0.002 0.001 939 1063 0.030 0.030
支持政党:れいわ新選組 3選択肢条件-4選択肢条件 0.013 0.014 939 1063 -0.012 0.012
支持政党:わからない 3選択肢条件-4選択肢条件 0.049 0.040 939 1063 0.041 0.041
支持政党:チームみらい 3選択肢条件-4選択肢条件 0.040 0.048 939 1063 -0.037 0.037
支持政党:中道改革連合 3選択肢条件-4選択肢条件 0.024 0.032 939 1063 -0.045 0.045
支持政党:公明党 3選択肢条件-4選択肢条件 0.011 0.009 939 1063 0.012 0.012
支持政党:参政党 3選択肢条件-4選択肢条件 0.049 0.040 939 1063 0.046 0.046
支持政党:国民民主党 3選択肢条件-4選択肢条件 0.081 0.066 939 1063 0.058 0.058
支持政党:支持政党なし 3選択肢条件-4選択肢条件 0.357 0.348 939 1063 0.018 0.018
支持政党:日本保守党 3選択肢条件-4選択肢条件 0.015 0.024 939 1063 -0.063 0.063
支持政党:日本共産党 3選択肢条件-4選択肢条件 0.014 0.021 939 1063 -0.053 0.053
支持政党:日本維新の会 3選択肢条件-4選択肢条件 0.049 0.060 939 1063 -0.049 0.049
支持政党:社会民主党 3選択肢条件-4選択肢条件 0.003 0.004 939 1063 -0.010 0.010
支持政党:立憲民主党 3選択肢条件-4選択肢条件 0.040 0.035 939 1063 0.030 0.030
支持政党:答えたくない 3選択肢条件-4選択肢条件 0.019 0.020 939 1063 -0.004 0.004
支持政党:自由民主党 3選択肢条件-4選択肢条件 0.233 0.239 939 1063 -0.013 0.013
地域:17 3選択肢条件-4選択肢条件 0.153 0.165 939 1063 -0.031 0.031
地域:27 3選択肢条件-4選択肢条件 0.201 0.200 939 1063 0.002 0.002
地域:35 3選択肢条件-4選択肢条件 0.085 0.092 939 1063 -0.025 0.025
地域:45 3選択肢条件-4選択肢条件 0.081 0.073 939 1063 0.028 0.028
地域:9 3選択肢条件-4選択肢条件 0.396 0.365 939 1063 0.064 0.064
左右自己位置づけ 3選択肢条件-4選択肢条件 5.384 5.373 939 1063 0.006 0.006
左右自己位置づけ:欠損 3選択肢条件-4選択肢条件 0.096 0.076 939 1063 0.070 0.070
年齢 3選択肢条件-5選択肢条件 42.353 43.582 939 1314 -0.108 0.108
年齢:欠損 3選択肢条件-5選択肢条件 0.052 0.042 939 1314 0.049 0.049
4年制大学以上 3選択肢条件-5選択肢条件 0.600 0.561 939 1314 0.078 0.078
学歴:欠損 3選択肢条件-5選択肢条件 0.009 0.010 939 1314 -0.014 0.014
女性 3選択肢条件-5選択肢条件 0.298 0.271 939 1314 0.060 0.060
性別:欠損 3選択肢条件-5選択肢条件 0.012 0.015 939 1314 -0.030 0.030
世帯年収(対数) 3選択肢条件-5選択肢条件 6.034 5.990 939 1314 0.031 0.031
支持政党:その他 3選択肢条件-5選択肢条件 0.002 0.003 939 1314 -0.018 0.018
支持政党:れいわ新選組 3選択肢条件-5選択肢条件 0.013 0.018 939 1314 -0.044 0.044
支持政党:わからない 3選択肢条件-5選択肢条件 0.049 0.036 939 1314 0.066 0.066
支持政党:チームみらい 3選択肢条件-5選択肢条件 0.040 0.051 939 1314 -0.050 0.050
支持政党:中道改革連合 3選択肢条件-5選択肢条件 0.024 0.030 939 1314 -0.036 0.036
支持政党:公明党 3選択肢条件-5選択肢条件 0.011 0.012 939 1314 -0.014 0.014
支持政党:参政党 3選択肢条件-5選択肢条件 0.049 0.040 939 1314 0.046 0.046
支持政党:国民民主党 3選択肢条件-5選択肢条件 0.081 0.069 939 1314 0.044 0.044
支持政党:支持政党なし 3選択肢条件-5選択肢条件 0.357 0.340 939 1314 0.035 0.035
支持政党:日本保守党 3選択肢条件-5選択肢条件 0.015 0.024 939 1314 -0.068 0.068
支持政党:日本共産党 3選択肢条件-5選択肢条件 0.014 0.021 939 1314 -0.052 0.052
支持政党:日本維新の会 3選択肢条件-5選択肢条件 0.049 0.046 939 1314 0.016 0.016
支持政党:社会民主党 3選択肢条件-5選択肢条件 0.003 0.005 939 1314 -0.022 0.022
支持政党:立憲民主党 3選択肢条件-5選択肢条件 0.040 0.048 939 1314 -0.036 0.036
支持政党:答えたくない 3選択肢条件-5選択肢条件 0.019 0.021 939 1314 -0.010 0.010
支持政党:自由民主党 3選択肢条件-5選択肢条件 0.233 0.237 939 1314 -0.008 0.008
地域:17 3選択肢条件-5選択肢条件 0.153 0.170 939 1314 -0.044 0.044
地域:27 3選択肢条件-5選択肢条件 0.201 0.196 939 1314 0.012 0.012
地域:35 3選択肢条件-5選択肢条件 0.085 0.074 939 1314 0.042 0.042
地域:45 3選択肢条件-5選択肢条件 0.081 0.091 939 1314 -0.034 0.034
地域:9 3選択肢条件-5選択肢条件 0.396 0.364 939 1314 0.067 0.067
左右自己位置づけ 3選択肢条件-5選択肢条件 5.384 5.414 939 1314 -0.017 0.017
左右自己位置づけ:欠損 3選択肢条件-5選択肢条件 0.096 0.088 939 1314 0.029 0.029
年齢 4選択肢条件-5選択肢条件 42.935 43.582 1063 1314 -0.056 0.056
年齢:欠損 4選択肢条件-5選択肢条件 0.047 0.042 1063 1314 0.025 0.025
4年制大学以上 4選択肢条件-5選択肢条件 0.583 0.561 1063 1314 0.045 0.045
学歴:欠損 4選択肢条件-5選択肢条件 0.008 0.010 1063 1314 -0.025 0.025
女性 4選択肢条件-5選択肢条件 0.285 0.271 1063 1314 0.031 0.031
性別:欠損 4選択肢条件-5選択肢条件 0.014 0.015 1063 1314 -0.009 0.009
世帯年収(対数) 4選択肢条件-5選択肢条件 5.964 5.990 1063 1314 -0.019 0.019
支持政党:その他 4選択肢条件-5選択肢条件 0.001 0.003 1063 1314 -0.047 0.047
支持政党:れいわ新選組 4選択肢条件-5選択肢条件 0.014 0.018 1063 1314 -0.033 0.033
支持政党:わからない 4選択肢条件-5選択肢条件 0.040 0.036 1063 1314 0.024 0.024
支持政党:チームみらい 4選択肢条件-5選択肢条件 0.048 0.051 1063 1314 -0.014 0.014
支持政党:中道改革連合 4選択肢条件-5選択肢条件 0.032 0.030 1063 1314 0.009 0.009
支持政党:公明党 4選択肢条件-5選択肢条件 0.009 0.012 1063 1314 -0.027 0.027
支持政党:参政党 4選択肢条件-5選択肢条件 0.040 0.040 1063 1314 0.000 0.000
支持政党:国民民主党 4選択肢条件-5選択肢条件 0.066 0.069 1063 1314 -0.014 0.014
支持政党:支持政党なし 4選択肢条件-5選択肢条件 0.348 0.340 1063 1314 0.017 0.017
支持政党:日本保守党 4選択肢条件-5選択肢条件 0.024 0.024 1063 1314 -0.005 0.005
支持政党:日本共産党 4選択肢条件-5選択肢条件 0.021 0.021 1063 1314 0.001 0.001
支持政党:日本維新の会 4選択肢条件-5選択肢条件 0.060 0.046 1063 1314 0.065 0.065
支持政党:社会民主党 4選択肢条件-5選択肢条件 0.004 0.005 1063 1314 -0.012 0.012
支持政党:立憲民主党 4選択肢条件-5選択肢条件 0.035 0.048 1063 1314 -0.066 0.066
支持政党:答えたくない 4選択肢条件-5選択肢条件 0.020 0.021 1063 1314 -0.006 0.006
支持政党:自由民主党 4選択肢条件-5選択肢条件 0.239 0.237 1063 1314 0.005 0.005
地域:17 4選択肢条件-5選択肢条件 0.165 0.170 1063 1314 -0.014 0.014
地域:27 4選択肢条件-5選択肢条件 0.200 0.196 1063 1314 0.010 0.010
地域:35 4選択肢条件-5選択肢条件 0.092 0.074 1063 1314 0.067 0.067
地域:45 4選択肢条件-5選択肢条件 0.073 0.091 1063 1314 -0.063 0.063
地域:9 4選択肢条件-5選択肢条件 0.365 0.364 1063 1314 0.003 0.003
左右自己位置づけ 4選択肢条件-5選択肢条件 5.373 5.414 1063 1314 -0.022 0.022
左右自己位置づけ:欠損 4選択肢条件-5選択肢条件 0.076 0.088 1063 1314 -0.041 0.041

図C8:条件平均の45度線診断

図C8は図C7と同じ回答者レベルの割付バランスを、各共変量の条件平均を標準化したうえで2条件ずつ45度線と比較したものである。

対角線データ <- assignment_balance_results$study3$diagonal_data %>%
  dplyr::mutate(
    比較 = paste0(condition_a, "選択肢条件-", condition_b, "選択肢条件")
  )

ラベル対象 <- 対角線データ %>%
  dplyr::group_by(比較) %>%
  dplyr::slice_max(abs_diagonal_deviation, n = 3, with_ties = FALSE) %>%
  dplyr::ungroup()

軸範囲 <- max(abs(c(対角線データ$x_mean, 対角線データ$y_mean)), na.rm = TRUE)
軸範囲 <- max(0.10, 軸範囲 * 1.15)

図C8 <- ggplot2::ggplot(対角線データ, ggplot2::aes(x = x_mean, y = y_mean)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.60) +
  ggplot2::geom_hline(yintercept = 0, linewidth = 0.25) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.25) +
  ggplot2::geom_point(shape = 21, fill = "white", size = 2.2) +
  ggplot2::geom_text(data = ラベル対象, ggplot2::aes(label = label), size = 2.6, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 比較, ncol = 3) +
  ggplot2::coord_equal(xlim = c(-軸範囲, 軸範囲), ylim = c(-軸範囲, 軸範囲)) +
  ggplot2::labs(x = "左側条件の標準化共変量平均", y = "右側条件の標準化共変量平均") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
図C8

表C10 <- assignment_balance_results$study3$summary %>%
  dplyr::transmute(
    変数 = label,
    `2選択肢条件の平均` = round(mean_condition_2, 3),
    `3選択肢条件の平均` = round(mean_condition_3, 3),
    `4選択肢条件の平均` = round(mean_condition_4, 3),
    `5選択肢条件の平均` = round(mean_condition_5, 3),
    `最大|SMD|` = round(max_abs_smd, 3),
    `Holm補正p値` = signif(p_holm, 3)
  )
knitr::kable(表日本語(表C10), format = "html", row.names = FALSE)
変数 2選択肢条件の平均 3選択肢条件の平均 4選択肢条件の平均 5選択肢条件の平均 最大|SMD| Holm補正p値
年齢 41.246 42.353 42.935 43.582 0.203 0.00415
女性 0.246 0.298 0.285 0.271 0.118 1.00000
4年制大学以上 0.609 0.600 0.583 0.561 0.098 1.00000
世帯年収(対数) 5.919 6.034 5.964 5.990 0.079 1.00000
支持政党:日本保守党 0.025 0.015 0.024 0.024 0.073 1.00000
左右自己位置づけ:欠損 0.080 0.096 0.076 0.088 0.070 1.00000
地域:17 0.145 0.153 0.165 0.170 0.067 1.00000
地域:9 0.383 0.396 0.365 0.364 0.067 1.00000
地域:35 0.085 0.085 0.092 0.074 0.067 1.00000
支持政党:立憲民主党 0.036 0.040 0.035 0.048 0.066 1.00000
支持政党:わからない 0.038 0.049 0.040 0.036 0.066 1.00000
支持政党:日本維新の会 0.053 0.049 0.060 0.046 0.065 1.00000
支持政党:日本共産党 0.022 0.014 0.021 0.021 0.064 1.00000
性別:欠損 0.020 0.012 0.014 0.015 0.063 1.00000
地域:45 0.087 0.081 0.073 0.091 0.063 1.00000
支持政党:国民民主党 0.068 0.081 0.066 0.069 0.058 1.00000
支持政党:支持政党なし 0.365 0.357 0.348 0.340 0.051 1.00000
支持政党:チームみらい 0.042 0.040 0.048 0.051 0.050 1.00000
年齢:欠損 0.052 0.052 0.047 0.042 0.049 1.00000
支持政党:その他 0.003 0.002 0.001 0.003 0.047 1.00000
支持政党:参政党 0.042 0.049 0.040 0.040 0.046 1.00000
支持政党:中道改革連合 0.032 0.024 0.032 0.030 0.046 1.00000
支持政党:れいわ新選組 0.015 0.013 0.014 0.018 0.044 1.00000
地域:27 0.214 0.201 0.200 0.196 0.043 1.00000
学歴:欠損 0.007 0.009 0.008 0.010 0.032 1.00000
左右自己位置づけ 5.430 5.384 5.373 5.414 0.031 1.00000
支持政党:社会民主党 0.003 0.003 0.004 0.005 0.029 1.00000
支持政党:答えたくない 0.017 0.019 0.020 0.021 0.028 1.00000
支持政党:公明党 0.011 0.011 0.009 0.012 0.027 1.00000
支持政党:自由民主党 0.228 0.233 0.239 0.237 0.027 1.00000

図C9:プロフィール属性水準の無作為提示

図C9は回答者の条件割付ではなく、各コンジョイント課題内で属性水準が設計どおり一様に提示されているかを確認するものである。

属性頻度 <- profile_randomization_results$study3$frequency %>%
  dplyr::mutate(
    属性 = 属性日本語(attribute),
    条件 = 条件日本語(party_n, "study3")
  )

表示ラベル <- 属性頻度 %>%
  dplyr::group_by(属性, 条件) %>%
  dplyr::slice_max(abs_deviation, n = 2, with_ties = FALSE) %>%
  dplyr::ungroup()

図C9 <- ggplot2::ggplot(属性頻度, ggplot2::aes(x = expected_share, y = observed_share, shape = 条件)) +
  ggplot2::geom_abline(intercept = 0, slope = 1, linetype = "dashed", linewidth = 0.65) +
  ggplot2::geom_point(size = 2.2, fill = "white") +
  ggplot2::geom_text(data = 表示ラベル, ggplot2::aes(label = level), size = 2.4, check_overlap = TRUE, vjust = -0.7) +
  ggplot2::facet_wrap(~ 属性, ncol = 3) +
  ggplot2::coord_equal() +
  ggplot2::labs(x = "設計上の期待比率", y = "観測比率", shape = "条件") +
  ggplot2::theme_bw(base_size = 10.5) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank(), legend.position = "bottom")
図C9

表C11 <- profile_randomization_results$study3$uniformity_tests %>%
  dplyr::transmute(
    条件 = 条件日本語(party_n, "study3"),
    属性 = 属性日本語(attribute),
    `カイ二乗値` = round(chi_square, 3),
    自由度 = df,
    p値 = signif(p_value, 3),
    `Holm補正p値` = signif(p_holm, 3),
    `最大絶対比率差` = round(max_abs_share_deviation, 4)
  )
knitr::kable(表日本語(表C11), format = "html", row.names = FALSE)
条件 属性 カイ二乗値 自由度 p値 Holm補正p値 最大絶対比率差
2選択肢条件 消費者物価指数(CPI) 0.000 2 1.000 1 0.0001
2選択肢条件 GDP成長率 1.386 2 0.500 1 0.0060
2選択肢条件 日経平均株価 0.555 2 0.758 1 0.0041
2選択肢条件 政党名 5.126 9 0.823 1 0.0056
2選択肢条件 失業率 1.668 2 0.434 1 0.0065
3選択肢条件 消費者物価指数(CPI) 0.545 2 0.762 1 0.0027
3選択肢条件 GDP成長率 0.073 2 0.964 1 0.0011
3選択肢条件 日経平均株価 0.833 2 0.659 1 0.0035
3選択肢条件 政党名 6.035 9 0.736 1 0.0031
3選択肢条件 失業率 2.016 2 0.365 1 0.0054
4選択肢条件 消費者物価指数(CPI) 2.607 2 0.272 1 0.0046
4選択肢条件 GDP成長率 0.104 2 0.949 1 0.0010
4選択肢条件 日経平均株価 3.268 2 0.195 1 0.0056
4選択肢条件 政党名 5.990 9 0.741 1 0.0031
4選択肢条件 失業率 0.107 2 0.948 1 0.0009
5選択肢条件 消費者物価指数(CPI) 0.879 2 0.644 1 0.0024
5選択肢条件 GDP成長率 0.107 2 0.948 1 0.0008
5選択肢条件 日経平均株価 2.946 2 0.229 1 0.0044
5選択肢条件 政党名 3.828 9 0.922 1 0.0020
5選択肢条件 失業率 5.593 2 0.061 1 0.0055
表C12 <- 属性頻度 %>%
  dplyr::transmute(
    条件,
    属性,
    水準 = level,
    観測数 = observed_n,
    総数 = total_n,
    観測比率 = round(observed_share, 4),
    期待比率 = round(expected_share, 4),
= round(deviation, 4)
  )
knitr::kable(表日本語(表C12), format = "html", row.names = FALSE)
条件 属性 水準 観測数 総数 観測比率 期待比率
2選択肢条件 消費者物価指数(CPI) CPI前期比±0ポイント 2387 7160 0.3334 0.3333 0.0000
2選択肢条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 2387 7160 0.3334 0.3333 0.0000
2選択肢条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 2386 7160 0.3332 0.3333 -0.0001
2選択肢条件 GDP成長率 GDP成長率±0% 2344 7160 0.3274 0.3333 -0.0060
2選択肢条件 GDP成長率 GDP成長率プラス1% 2425 7160 0.3387 0.3333 0.0054
2選択肢条件 GDP成長率 GDP成長率マイナス1% 2391 7160 0.3339 0.3333 0.0006
2選択肢条件 日経平均株価 日経平均前月同期比プラス1000円 2357 7160 0.3292 0.3333 -0.0041
2選択肢条件 日経平均株価 日経平均前月同期比マイナス1000円 2400 7160 0.3352 0.3333 0.0019
2選択肢条件 日経平均株価 日経平均前月同期比変わらず 2403 7160 0.3356 0.3333 0.0023
2選択肢条件 政党名 れいわ新選組 676 7160 0.0944 0.1000 -0.0056
2選択肢条件 政党名 チームみらい 730 7160 0.1020 0.1000 0.0020
2選択肢条件 政党名 中道改革連合 728 7160 0.1017 0.1000 0.0017
2選択肢条件 政党名 公明党 700 7160 0.0978 0.1000 -0.0022
2選択肢条件 政党名 参政党 746 7160 0.1042 0.1000 0.0042
2選択肢条件 政党名 国民民主党 703 7160 0.0982 0.1000 -0.0018
2選択肢条件 政党名 日本共産党 708 7160 0.0989 0.1000 -0.0011
2選択肢条件 政党名 日本維新の会 734 7160 0.1025 0.1000 0.0025
2選択肢条件 政党名 立憲民主党 720 7160 0.1006 0.1000 0.0006
2選択肢条件 政党名 自由民主党 715 7160 0.0999 0.1000 -0.0001
2選択肢条件 失業率 失業率前期比±0% 2433 7160 0.3398 0.3333 0.0065
2選択肢条件 失業率 失業率前期比プラス1% 2383 7160 0.3328 0.3333 -0.0005
2選択肢条件 失業率 失業率前期比マイナス1% 2344 7160 0.3274 0.3333 -0.0060
3選択肢条件 消費者物価指数(CPI) CPI前期比±0ポイント 4728 14085 0.3357 0.3333 0.0023
3選択肢条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 4700 14085 0.3337 0.3333 0.0004
3選択肢条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 4657 14085 0.3306 0.3333 -0.0027
3選択肢条件 GDP成長率 GDP成長率±0% 4704 14085 0.3340 0.3333 0.0006
3選択肢条件 GDP成長率 GDP成長率プラス1% 4701 14085 0.3338 0.3333 0.0004
3選択肢条件 GDP成長率 GDP成長率マイナス1% 4680 14085 0.3323 0.3333 -0.0011
3選択肢条件 日経平均株価 日経平均前月同期比プラス1000円 4661 14085 0.3309 0.3333 -0.0024
3選択肢条件 日経平均株価 日経平均前月同期比マイナス1000円 4679 14085 0.3322 0.3333 -0.0011
3選択肢条件 日経平均株価 日経平均前月同期比変わらず 4745 14085 0.3369 0.3333 0.0035
3選択肢条件 政党名 れいわ新選組 1388 14085 0.0985 0.1000 -0.0015
3選択肢条件 政党名 チームみらい 1403 14085 0.0996 0.1000 -0.0004
3選択肢条件 政党名 中道改革連合 1451 14085 0.1030 0.1000 0.0030
3選択肢条件 政党名 公明党 1382 14085 0.0981 0.1000 -0.0019
3選択肢条件 政党名 参政党 1376 14085 0.0977 0.1000 -0.0023
3選択肢条件 政党名 国民民主党 1446 14085 0.1027 0.1000 0.0027
3選択肢条件 政党名 日本共産党 1452 14085 0.1031 0.1000 0.0031
3選択肢条件 政党名 日本維新の会 1413 14085 0.1003 0.1000 0.0003
3選択肢条件 政党名 立憲民主党 1376 14085 0.0977 0.1000 -0.0023
3選択肢条件 政党名 自由民主党 1398 14085 0.0993 0.1000 -0.0007
3選択肢条件 失業率 失業率前期比±0% 4771 14085 0.3387 0.3333 0.0054
3選択肢条件 失業率 失業率前期比プラス1% 4677 14085 0.3321 0.3333 -0.0013
3選択肢条件 失業率 失業率前期比マイナス1% 4637 14085 0.3292 0.3333 -0.0041
4選択肢条件 消費者物価指数(CPI) CPI前期比±0ポイント 7180 21260 0.3377 0.3333 0.0044
4選択肢条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 6988 21260 0.3287 0.3333 -0.0046
4選択肢条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 7092 21260 0.3336 0.3333 0.0003
4選択肢条件 GDP成長率 GDP成長率±0% 7090 21260 0.3335 0.3333 0.0002
4選択肢条件 GDP成長率 GDP成長率プラス1% 7104 21260 0.3341 0.3333 0.0008
4選択肢条件 GDP成長率 GDP成長率マイナス1% 7066 21260 0.3324 0.3333 -0.0010
4選択肢条件 日経平均株価 日経平均前月同期比プラス1000円 7057 21260 0.3319 0.3333 -0.0014
4選択肢条件 日経平均株価 日経平均前月同期比マイナス1000円 7206 21260 0.3389 0.3333 0.0056
4選択肢条件 日経平均株価 日経平均前月同期比変わらず 6997 21260 0.3291 0.3333 -0.0042
4選択肢条件 政党名 れいわ新選組 2164 21260 0.1018 0.1000 0.0018
4選択肢条件 政党名 チームみらい 2144 21260 0.1008 0.1000 0.0008
4選択肢条件 政党名 中道改革連合 2079 21260 0.0978 0.1000 -0.0022
4選択肢条件 政党名 公明党 2150 21260 0.1011 0.1000 0.0011
4選択肢条件 政党名 参政党 2126 21260 0.1000 0.1000 0.0000
4選択肢条件 政党名 国民民主党 2115 21260 0.0995 0.1000 -0.0005
4選択肢条件 政党名 日本共産党 2184 21260 0.1027 0.1000 0.0027
4選択肢条件 政党名 日本維新の会 2108 21260 0.0992 0.1000 -0.0008
4選択肢条件 政党名 立憲民主党 2060 21260 0.0969 0.1000 -0.0031
4選択肢条件 政党名 自由民主党 2130 21260 0.1002 0.1000 0.0002
4選択肢条件 失業率 失業率前期比±0% 7067 21260 0.3324 0.3333 -0.0009
4選択肢条件 失業率 失業率前期比プラス1% 7087 21260 0.3333 0.3333 0.0000
4選択肢条件 失業率 失業率前期比マイナス1% 7106 21260 0.3342 0.3333 0.0009
5選択肢条件 消費者物価指数(CPI) CPI前期比±0ポイント 10978 32850 0.3342 0.3333 0.0009
5選択肢条件 消費者物価指数(CPI) CPI前期比プラス1ポイント 11001 32850 0.3349 0.3333 0.0016
5選択肢条件 消費者物価指数(CPI) CPI前期比マイナス1ポイント 10871 32850 0.3309 0.3333 -0.0024
5選択肢条件 GDP成長率 GDP成長率±0% 10924 32850 0.3325 0.3333 -0.0008
5選択肢条件 GDP成長率 GDP成長率プラス1% 10954 32850 0.3335 0.3333 0.0001
5選択肢条件 GDP成長率 GDP成長率マイナス1% 10972 32850 0.3340 0.3333 0.0007
5選択肢条件 日経平均株価 日経平均前月同期比プラス1000円 11046 32850 0.3363 0.3333 0.0029
5選択肢条件 日経平均株価 日経平均前月同期比マイナス1000円 10806 32850 0.3289 0.3333 -0.0044
5選択肢条件 日経平均株価 日経平均前月同期比変わらず 10998 32850 0.3348 0.3333 0.0015
5選択肢条件 政党名 れいわ新選組 3277 32850 0.0998 0.1000 -0.0002
5選択肢条件 政党名 チームみらい 3351 32850 0.1020 0.1000 0.0020
5選択肢条件 政党名 中道改革連合 3311 32850 0.1008 0.1000 0.0008
5選択肢条件 政党名 公明党 3243 32850 0.0987 0.1000 -0.0013
5選択肢条件 政党名 参政党 3280 32850 0.0998 0.1000 -0.0002
5選択肢条件 政党名 国民民主党 3315 32850 0.1009 0.1000 0.0009
5選択肢条件 政党名 日本共産党 3271 32850 0.0996 0.1000 -0.0004
5選択肢条件 政党名 日本維新の会 3218 32850 0.0980 0.1000 -0.0020
5選択肢条件 政党名 立憲民主党 3290 32850 0.1002 0.1000 0.0002
5選択肢条件 政党名 自由民主党 3294 32850 0.1003 0.1000 0.0003
5選択肢条件 失業率 失業率前期比±0% 10965 32850 0.3338 0.3333 0.0005
5選択肢条件 失業率 失業率前期比プラス1% 10768 32850 0.3278 0.3333 -0.0055
5選択肢条件 失業率 失業率前期比マイナス1% 11117 32850 0.3384 0.3333 0.0051

C.4 標本減少とスクリーニング

実験1(2023年)

実験1標本減少 <- readr::read_csv(study_csv("study1", "table_sample_attrition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(
    段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))
  ) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験1標本減少, format = "html", row.names = FALSE, caption = "表C13:実験1の標本減少")
表C13:実験1の標本減少
順序 段階 質問・変数 残存N 当該段階での除外N 前段階からの残存率(%) 初期標本からの残存率(%)
1 Qualtricsの質問文・ImportId行を除外 ResponseId 3826 0 100 100
2 初回同意 Q1.1 3730 96 97.5 97.5
3 割付されたコンジョイント・ブロックに到達 Q3.1/Q4.1/Q5.1/Q6.1 または最初の選択課題 3426 304 91.8 89.5
4 選択課題1を有効回答 条件別 choice task 1 3426 0 100 89.5
5 選択課題2を有効回答 条件別 choice task 2 3417 9 99.7 89.3
6 選択課題3を有効回答 条件別 choice task 3 3412 5 99.9 89.2
7 選択課題4を有効回答 条件別 choice task 4 3410 2 99.9 89.1
8 選択課題5を有効回答 条件別 choice task 5 3407 3 99.9 89
9 最終送信同意 Q10.1 3382 25 99.3 88.4
10 最終分析標本 全基準の積集合 3382 0 100 88.4
実験1条件別標本 <- readr::read_csv(study_csv("study1", "table_sample_attrition_by_condition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(
    条件 = 条件日本語(条件, "study1"),
    段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))
  ) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験1条件別標本, format = "html", row.names = FALSE, caption = "表C14:実験1の条件別標本減少")
表C14:実験1の条件別標本減少
条件 順序 段階 残存N 当該段階での除外N 条件開始時からの残存率(%)
2政党条件 1 割付条件を識別 821 0 100
2政党条件 2 選択課題1 821 0 100
2政党条件 3 選択課題2 821 0 100
2政党条件 4 選択課題3 820 1 99.9
2政党条件 5 選択課題4 820 0 99.9
2政党条件 6 選択課題5 820 0 99.9
2政党条件 7 最終送信同意 815 5 99.3
2政党条件 8 最終分析標本 815 0 99.3
3政党条件 1 割付条件を識別 855 0 100
3政党条件 2 選択課題1 855 0 100
3政党条件 3 選択課題2 852 3 99.6
3政党条件 4 選択課題3 851 1 99.5
3政党条件 5 選択課題4 850 1 99.4
3政党条件 6 選択課題5 849 1 99.3
3政党条件 7 最終送信同意 843 6 98.6
3政党条件 8 最終分析標本 843 0 98.6
4政党条件 1 割付条件を識別 894 0 100
4政党条件 2 選択課題1 894 0 100
4政党条件 3 選択課題2 891 3 99.7
4政党条件 4 選択課題3 889 2 99.4
4政党条件 5 選択課題4 889 0 99.4
4政党条件 6 選択課題5 888 1 99.3
4政党条件 7 最終送信同意 882 6 98.7
4政党条件 8 最終分析標本 882 0 98.7
5政党条件 1 割付条件を識別 856 0 100
5政党条件 2 選択課題1 856 0 100
5政党条件 3 選択課題2 853 3 99.6
5政党条件 4 選択課題3 852 1 99.5
5政党条件 5 選択課題4 851 1 99.4
5政党条件 6 選択課題5 850 1 99.3
5政党条件 7 最終送信同意 842 8 98.4
5政党条件 8 最終分析標本 842 0 98.4

実験2(2026年)

実験2標本減少 <- readr::read_csv(study_csv("study2", "table_sample_attrition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験2標本減少, format = "html", row.names = FALSE, caption = "表C17:実験2の標本減少")
表C17:実験2の標本減少
順序 段階 質問・変数 残存N 当該段階での除外N 前段階からの残存率(%) 初期標本からの残存率(%)
1 Qualtricsの質問文・ImportId行を除外 ResponseId 7365 0 100 100
2 初回同意 Q1.1 7114 251 96.6 96.6
3 割付されたコンジョイント・ブロックに到達 Q3.1/Q4.1/Q5.1/Q6.1 または最初の選択課題 7113 1 100 96.6
4 選択課題1を有効回答 条件別 choice task 1 7113 0 100 96.6
5 選択課題2を有効回答 条件別 choice task 2 7113 0 100 96.6
6 選択課題3を有効回答 条件別 choice task 3 7113 0 100 96.6
7 選択課題4を有効回答 条件別 choice task 4 7113 0 100 96.6
8 選択課題5を有効回答 条件別 choice task 5 7113 0 100 96.6
9 提示された選択肢数を正答 条件別に自動検出した選択肢数確認質問 4350 2763 61.2 59.1
10 イデオロギー行列の指示項目に正答 Q25.1_10 4241 109 97.5 57.6
11 最終送信同意 Q9.1 4192 49 98.8 56.9
12 最終分析標本 全基準の積集合 4192 0 100 56.9
実験2条件別標本 <- readr::read_csv(study_csv("study2", "table_sample_attrition_by_condition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), 段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験2条件別標本, format = "html", row.names = FALSE, caption = "表C18:実験2の条件別標本減少")
表C18:実験2の条件別標本減少
条件 順序 段階 残存N 当該段階での除外N 条件開始時からの残存率(%)
2政党条件 1 割付条件を識別 1785 0 100
2政党条件 2 選択課題1 1785 0 100
2政党条件 3 選択課題2 1785 0 100
2政党条件 4 選択課題3 1785 0 100
2政党条件 5 選択課題4 1785 0 100
2政党条件 6 選択課題5 1785 0 100
2政党条件 7 選択肢数確認 734 1051 41.1
2政党条件 8 指示項目 716 18 40.1
2政党条件 9 最終送信同意 711 5 39.8
2政党条件 10 最終分析標本 711 0 39.8
3政党条件 1 割付条件を識別 1791 0 100
3政党条件 2 選択課題1 1791 0 100
3政党条件 3 選択課題2 1791 0 100
3政党条件 4 選択課題3 1791 0 100
3政党条件 5 選択課題4 1791 0 100
3政党条件 6 選択課題5 1791 0 100
3政党条件 7 選択肢数確認 1098 693 61.3
3政党条件 8 指示項目 1069 29 59.7
3政党条件 9 最終送信同意 1062 7 59.3
3政党条件 10 最終分析標本 1062 0 59.3
4政党条件 1 割付条件を識別 1741 0 100
4政党条件 2 選択課題1 1741 0 100
4政党条件 3 選択課題2 1741 0 100
4政党条件 4 選択課題3 1741 0 100
4政党条件 5 選択課題4 1741 0 100
4政党条件 6 選択課題5 1741 0 100
4政党条件 7 選択肢数確認 1141 600 65.5
4政党条件 8 指示項目 1113 28 63.9
4政党条件 9 最終送信同意 1097 16 63
4政党条件 10 最終分析標本 1097 0 63
5政党条件 1 割付条件を識別 1796 0 100
5政党条件 2 選択課題1 1796 0 100
5政党条件 3 選択課題2 1796 0 100
5政党条件 4 選択課題3 1796 0 100
5政党条件 5 選択課題4 1796 0 100
5政党条件 6 選択課題5 1796 0 100
5政党条件 7 選択肢数確認 1377 419 76.7
5政党条件 8 指示項目 1343 34 74.8
5政党条件 9 最終送信同意 1322 21 73.6
5政党条件 10 最終分析標本 1322 0 73.6
実験2操作確認 <- readr::read_csv(study_csv("study2", "table_manipulation_check.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", response = "回答", status = "判定", n = "N")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験2操作確認, format = "html", row.names = FALSE, caption = "表C19:実験2の選択肢数操作確認")
表C19:実験2の選択肢数操作確認
条件 回答 正答 N
2政党条件 1 不正答・欠損 29
2政党条件 2 正答 734
2政党条件 3 不正答・欠損 91
2政党条件 4 不正答・欠損 124
2政党条件 5 不正答・欠損 559
2政党条件 6 不正答・欠損 248
3政党条件 1 不正答・欠損 25
3政党条件 2 不正答・欠損 64
3政党条件 3 正答 1098
3政党条件 4 不正答・欠損 66
3政党条件 5 不正答・欠損 329
3政党条件 6 不正答・欠損 209
4政党条件 1 不正答・欠損 30
4政党条件 2 不正答・欠損 46
4政党条件 3 不正答・欠損 49
4政党条件 4 正答 1141
4政党条件 5 不正答・欠損 289
4政党条件 6 不正答・欠損 186
5政党条件 1 不正答・欠損 37
5政党条件 2 不正答・欠損 53
5政党条件 3 不正答・欠損 76
5政党条件 4 不正答・欠損 90
5政党条件 5 正答 1377
5政党条件 6 不正答・欠損 163
実験2指示項目 <- readr::read_csv(study_csv("study2", "table_attention_check.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, response = "回答コード", status = "判定", n = "N")) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験2指示項目, format = "html", row.names = FALSE, caption = "表C20:実験2の指示項目")
表C20:実験2の指示項目
回答 判定 N
1 不正答・欠損 12
12 不正答・欠損 7
13 不正答・欠損 6
14 不正答・欠損 7
15 不正答・欠損 70
16 不正答・欠損 26
2 不正答・欠損 8
3 正答 6842
4 不正答・欠損 24
5 不正答・欠損 12
6 不正答・欠損 83
7 不正答・欠損 12
8 不正答・欠損 6
未実施・欠損 不正答・欠損 250

実験3(2026年)

実験3標本減少 <- readr::read_csv(study_csv("study3", "table_sample_attrition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験3標本減少, format = "html", row.names = FALSE, caption = "表C21:実験3の標本減少")
表C21:実験3の標本減少
順序 段階 質問・変数 残存N 当該段階での除外N 前段階からの残存率(%) 初期標本からの残存率(%)
1 Qualtricsの質問文・ImportId行を除外 ResponseId 7012 0 100 100
2 初回同意 Q1.1 6852 160 97.7 97.7
3 割付されたコンジョイント・ブロックに到達 Q3.1/Q4.1/Q5.1/Q6.1 または最初の選択課題 6852 0 100 97.7
4 選択課題1を有効回答 条件別 choice task 1 6852 0 100 97.7
5 選択課題2を有効回答 条件別 choice task 2 6852 0 100 97.7
6 選択課題3を有効回答 条件別 choice task 3 6852 0 100 97.7
7 選択課題4を有効回答 条件別 choice task 4 6852 0 100 97.7
8 選択課題5を有効回答 条件別 choice task 5 6852 0 100 97.7
9 提示された選択肢数を正答 条件別に自動検出した選択肢数確認質問 4184 2668 61.1 59.7
10 イデオロギー行列の指示項目に正答 Q25.1_10 4053 131 96.9 57.8
11 最終送信同意 Q8.1 4032 21 99.5 57.5
12 最終分析標本 全基準の積集合 4032 0 100 57.5
実験3条件別標本 <- readr::read_csv(study_csv("study3", "table_sample_attrition_by_condition.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), 段階 = stringr::str_replace_all(段階, c("choice_task([1-5])" = "選択課題\\1", "Choice task ([1-5])" = "選択課題\\1"))) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験3条件別標本, format = "html", row.names = FALSE, caption = "表C22:実験3の条件別標本減少")
表C22:実験3の条件別標本減少
条件 順序 段階 残存N 当該段階での除外N 条件開始時からの残存率(%)
2選択肢条件 1 割付条件を識別 1684 0 100
2選択肢条件 2 選択課題1 1684 0 100
2選択肢条件 3 選択課題2 1684 0 100
2選択肢条件 4 選択課題3 1684 0 100
2選択肢条件 5 選択課題4 1684 0 100
2選択肢条件 6 選択課題5 1684 0 100
2選択肢条件 7 選択肢数確認 741 943 44
2選択肢条件 8 指示項目 721 20 42.8
2選択肢条件 9 最終送信同意 716 5 42.5
2選択肢条件 10 最終分析標本 716 0 42.5
3選択肢条件 1 割付条件を識別 1769 0 100
3選択肢条件 2 選択課題1 1769 0 100
3選択肢条件 3 選択課題2 1769 0 100
3選択肢条件 4 選択課題3 1769 0 100
3選択肢条件 5 選択課題4 1769 0 100
3選択肢条件 6 選択課題5 1769 0 100
3選択肢条件 7 選択肢数確認 982 787 55.5
3選択肢条件 8 指示項目 944 38 53.4
3選択肢条件 9 最終送信同意 939 5 53.1
3選択肢条件 10 最終分析標本 939 0 53.1
4選択肢条件 1 割付条件を識別 1722 0 100
4選択肢条件 2 選択課題1 1722 0 100
4選択肢条件 3 選択課題2 1722 0 100
4選択肢条件 4 選択課題3 1722 0 100
4選択肢条件 5 選択課題4 1722 0 100
4選択肢条件 6 選択課題5 1722 0 100
4選択肢条件 7 選択肢数確認 1099 623 63.8
4選択肢条件 8 指示項目 1064 35 61.8
4選択肢条件 9 最終送信同意 1063 1 61.7
4選択肢条件 10 最終分析標本 1063 0 61.7
5選択肢条件 1 割付条件を識別 1677 0 100
5選択肢条件 2 選択課題1 1677 0 100
5選択肢条件 3 選択課題2 1677 0 100
5選択肢条件 4 選択課題3 1677 0 100
5選択肢条件 5 選択課題4 1677 0 100
5選択肢条件 6 選択課題5 1677 0 100
5選択肢条件 7 選択肢数確認 1362 315 81.2
5選択肢条件 8 指示項目 1324 38 79
5選択肢条件 9 最終送信同意 1314 10 78.4
5選択肢条件 10 最終分析標本 1314 0 78.4
実験3操作確認 <- readr::read_csv(study_csv("study3", "table_manipulation_check.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", response = "回答", status = "判定", n = "N")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験3操作確認, format = "html", row.names = FALSE, caption = "表C23:実験3の選択肢数操作確認")
表C23:実験3の選択肢数操作確認
条件 回答 正答 N
2選択肢条件 1 不正答・欠損 15
2選択肢条件 2 正答 741
2選択肢条件 3 不正答・欠損 47
2選択肢条件 4 不正答・欠損 121
2選択肢条件 5 不正答・欠損 603
2選択肢条件 6 不正答・欠損 157
3選択肢条件 1 不正答・欠損 19
3選択肢条件 2 不正答・欠損 27
3選択肢条件 3 正答 982
3選択肢条件 4 不正答・欠損 93
3選択肢条件 5 不正答・欠損 490
3選択肢条件 6 不正答・欠損 158
4選択肢条件 1 不正答・欠損 16
4選択肢条件 2 不正答・欠損 18
4選択肢条件 3 不正答・欠損 38
4選択肢条件 4 正答 1099
4選択肢条件 5 不正答・欠損 415
4選択肢条件 6 不正答・欠損 135
4選択肢条件 未実施・欠損 不正答・欠損 1
5選択肢条件 1 不正答・欠損 20
5選択肢条件 2 不正答・欠損 27
5選択肢条件 3 不正答・欠損 36
5選択肢条件 4 不正答・欠損 89
5選択肢条件 5 正答 1362
5選択肢条件 6 不正答・欠損 143
実験3指示項目 <- readr::read_csv(study_csv("study3", "table_attention_check.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, response = "回答コード", status = "判定", n = "N")) %>%
  dplyr::mutate(dplyr::across(dplyr::everything(), ~ tidyr::replace_na(as.character(.x), "—")))
knitr::kable(実験3指示項目, format = "html", row.names = FALSE, caption = "表C24:実験3の指示項目")
表C24:実験3の指示項目
回答 判定 N
1 不正答・欠損 8
12 不正答・欠損 9
13 不正答・欠損 4
14 不正答・欠損 7
15 不正答・欠損 94
16 不正答・欠損 11
2 不正答・欠損 11
3 正答 6545
4 不正答・欠損 35
5 不正答・欠損 14
6 不正答・欠損 89
7 不正答・欠損 17
8 不正答・欠損 7
未実施・欠損 不正答・欠損 161

D. 本文図の再現

この節の図(表)番号は本文と一致したものである。本文の分析結果で用いる図は図4から図9までであり、実験2のAMCEは本文図には表示せず、補遺Eに掲示されている。

図4:実験1(2023年)の共変量調整済みAMCE

図4データ <- study1_env$amce_plot_df_cov_facet
図4 <- ggplot2::ggplot(
  図4データ,
  ggplot2::aes(x = estimate_pp, y = label, shape = party_n, linetype = party_n, group = party_n)
) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.45, color = "grey35") +
  ggplot2::geom_errorbarh(
    ggplot2::aes(xmin = conf.low_pp, xmax = conf.high_pp),
    position = ggplot2::position_dodge(width = 0.65), height = 0.16, linewidth = 0.55
  ) +
  ggplot2::geom_point(position = ggplot2::position_dodge(width = 0.65), size = 2.5, fill = "white", stroke = 0.8) +
  ggplot2::facet_grid(attribute_facet ~ ., scales = "free_y", space = "free_y", switch = "y") +
  ggplot2::scale_shape_manual(values = c("2政党" = 16, "3政党" = 17, "4政党" = 15, "5政党" = 1)) +
  ggplot2::scale_linetype_manual(values = c("2政党" = "solid", "3政党" = "dashed", "4政党" = "dotted", "5政党" = "dotdash")) +
  ggplot2::labs(x = "選択確率の変化", y = NULL, shape = "政党数条件", linetype = "政党数条件") +
  ggplot2::theme_bw(base_size = 12) +
  ggplot2::theme(legend.position = "top", panel.grid.major.y = ggplot2::element_blank(), panel.grid.minor = ggplot2::element_blank())
図4

表D1 <- readr::read_csv(study_csv("study1", "table_amce_covariate_adjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表D1), format = "html", row.names = FALSE, caption = "表D1:図4に対応する共変量調整済みAMCE")
表D1:図4に対応する共変量調整済みAMCE
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2政党条件 政策位置 右派・保守的 -2.51 1.44 -5.33 0.32 .082 815
2政党条件 政策位置 左派・革新的 -8.04 1.43 -10.85 -5.23 < .001 815
2政党条件 与党/野党 与党 4.78 1.21 2.41 7.15 < .001 815
2政党条件 GDP成長率 GDP:プラス1% 7.73 1.40 4.99 10.47 < .001 815
2政党条件 GDP成長率 GDP:マイナス1% -2.75 1.38 -5.45 -0.05 .046 815
2政党条件 日経平均 日経平均:プラス1000円 6.35 1.39 3.63 9.07 < .001 815
2政党条件 日経平均 日経平均:マイナス1000円 -5.44 1.34 -8.07 -2.81 < .001 815
2政党条件 議席数 議席数:10~49 2.16 1.74 -1.25 5.57 .214 815
2政党条件 議席数 議席数:50~99 7.55 1.76 4.09 11.01 < .001 815
2政党条件 議席数 議席数:100~199 8.90 1.78 5.41 12.40 < .001 815
2政党条件 議席数 議席数:200以上 10.73 1.84 7.13 14.34 < .001 815
2政党条件 CPI CPI:プラス1ポイント -0.14 1.38 -2.85 2.57 .918 815
2政党条件 CPI CPI:マイナス1ポイント -1.13 1.38 -3.83 1.57 .413 815
2政党条件 失業率 失業率:プラス1% -4.50 1.38 -7.22 -1.79 .001 815
2政党条件 失業率 失業率:マイナス1% -2.83 1.39 -5.55 -0.10 .042 815
3政党条件 政策位置 右派・保守的 -4.79 1.22 -7.18 -2.40 < .001 843
3政党条件 政策位置 左派・革新的 -8.99 1.22 -11.39 -6.60 < .001 843
3政党条件 与党/野党 与党 3.50 1.10 1.35 5.65 .001 843
3政党条件 GDP成長率 GDP:プラス1% 8.05 1.02 6.05 10.06 < .001 843
3政党条件 GDP成長率 GDP:マイナス1% -2.67 0.96 -4.55 -0.80 .005 843
3政党条件 日経平均 日経平均:プラス1000円 6.07 1.06 3.99 8.14 < .001 843
3政党条件 日経平均 日経平均:マイナス1000円 -4.23 1.04 -6.28 -2.19 < .001 843
3政党条件 議席数 議席数:10~49 3.66 1.24 1.23 6.09 .003 843
3政党条件 議席数 議席数:50~99 8.36 1.28 5.86 10.86 < .001 843
3政党条件 議席数 議席数:100~199 11.70 1.48 8.79 14.61 < .001 843
3政党条件 議席数 議席数:200以上 11.28 1.52 8.29 14.26 < .001 843
3政党条件 CPI CPI:プラス1ポイント 1.15 1.01 -0.82 3.13 .253 843
3政党条件 CPI CPI:マイナス1ポイント 0.14 1.01 -1.84 2.12 .892 843
3政党条件 失業率 失業率:プラス1% -3.40 1.05 -5.47 -1.34 .001 843
3政党条件 失業率 失業率:マイナス1% -2.05 1.06 -4.12 0.03 .053 843
4政党条件 政策位置 右派・保守的 -5.27 1.00 -7.22 -3.32 < .001 882
4政党条件 政策位置 左派・革新的 -8.28 0.99 -10.22 -6.34 < .001 882
4政党条件 与党/野党 与党 4.27 0.95 2.40 6.14 < .001 882
4政党条件 GDP成長率 GDP:プラス1% 7.39 0.88 5.67 9.11 < .001 882
4政党条件 GDP成長率 GDP:マイナス1% -3.46 0.78 -4.98 -1.94 < .001 882
4政党条件 日経平均 日経平均:プラス1000円 3.24 0.86 1.55 4.93 < .001 882
4政党条件 日経平均 日経平均:マイナス1000円 -5.21 0.77 -6.71 -3.70 < .001 882
4政党条件 議席数 議席数:10~49 3.79 0.89 2.05 5.54 < .001 882
4政党条件 議席数 議席数:50~99 6.69 0.99 4.74 8.63 < .001 882
4政党条件 議席数 議席数:100~199 10.17 1.14 7.93 12.41 < .001 882
4政党条件 議席数 議席数:200以上 9.91 1.30 7.36 12.47 < .001 882
4政党条件 CPI CPI:プラス1ポイント 2.79 0.81 1.21 4.38 < .001 882
4政党条件 CPI CPI:マイナス1ポイント 0.05 0.81 -1.53 1.62 .955 882
4政党条件 失業率 失業率:プラス1% -3.58 0.84 -5.23 -1.93 < .001 882
4政党条件 失業率 失業率:マイナス1% -0.44 0.82 -2.05 1.17 .589 882
5政党条件 政策位置 右派・保守的 -4.37 0.85 -6.04 -2.70 < .001 842
5政党条件 政策位置 左派・革新的 -6.56 0.85 -8.23 -4.89 < .001 842
5政党条件 与党/野党 与党 4.94 0.87 3.23 6.65 < .001 842
5政党条件 GDP成長率 GDP:プラス1% 6.42 0.77 4.91 7.93 < .001 842
5政党条件 GDP成長率 GDP:マイナス1% -3.26 0.67 -4.58 -1.94 < .001 842
5政党条件 日経平均 日経平均:プラス1000円 3.79 0.72 2.38 5.20 < .001 842
5政党条件 日経平均 日経平均:マイナス1000円 -4.52 0.65 -5.79 -3.25 < .001 842
5政党条件 議席数 議席数:10~49 3.80 0.71 2.41 5.18 < .001 842
5政党条件 議席数 議席数:50~99 8.22 0.93 6.40 10.04 < .001 842
5政党条件 議席数 議席数:100~199 9.81 1.09 7.68 11.94 < .001 842
5政党条件 議席数 議席数:200以上 10.13 1.14 7.90 12.36 < .001 842
5政党条件 CPI CPI:プラス1ポイント 0.89 0.69 -0.45 2.23 .194 842
5政党条件 CPI CPI:マイナス1ポイント -1.16 0.67 -2.48 0.16 .086 842
5政党条件 失業率 失業率:プラス1% -2.97 0.71 -4.36 -1.58 < .001 842
5政党条件 失業率 失業率:マイナス1% -0.07 0.72 -1.48 1.34 .924 842

図5:実験1(2023年)の政党・経済手がかりの重要度と相対比重

図5重要度データ <- study1_env$relative_panel_adjusted_data
図5相対比重データ <- study1_env$relative_panel_b_data
図5パネルA <- study1_env$relative_panel_adjusted
図5パネルB <- study1_env$relative_panel_c
図5 <- (図5パネルA | 図5パネルB) + patchwork::plot_layout(widths = c(1, 1))
図5

表D2 <- readr::read_csv(study_csv("study1", "table_marginal_means.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", level = "水準")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study1"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D2), format = "html", row.names = FALSE, caption = "表D2:限界平均")
表D2:限界平均
条件 手がかり群 属性 水準 限界平均(%) クラスタSE(pp) 95% CI下限(%) 95% CI上限(%) プロファイル数 回答者数
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 50.37 0.80 48.81 51.94 2672 799
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 50.36 0.82 48.76 51.96 2780 804
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 49.26 0.82 47.64 50.88 2698 800
2政党 経済の手がかり GDP成長率 GDP成長率±0% 48.09 0.81 46.50 49.67 2716 797
2政党 経済の手がかり GDP成長率 GDP成長率プラス1% 56.04 0.82 54.44 57.64 2791 801
2政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 45.59 0.83 43.97 47.21 2643 800
2政党 政党の手がかり 与野党地位 与党 52.41 0.61 51.22 53.61 4146 815
2政党 政党の手がかり 与野党地位 野党 47.50 0.63 46.27 48.74 4004 814
2政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 56.27 0.82 54.65 57.88 2721 802
2政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 44.13 0.79 42.58 45.68 2726 798
2政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 49.61 0.79 48.07 51.16 2703 792
2政党 政党の手がかり 政策位置 中道 53.44 0.81 51.86 55.02 2717 800
2政党 政党の手がかり 政策位置 右派・保守的 51.09 0.91 49.31 52.87 2711 801
2政党 政党の手がかり 政策位置 左派・革新的 45.48 0.89 43.73 47.23 2722 802
2政党 政党の手がかり 議席数 100~199 53.13 1.13 50.92 55.34 1662 744
2政党 政党の手がかり 議席数 10~49 46.26 1.15 44.01 48.51 1565 721
2政党 政党の手がかり 議席数 10以下 44.13 1.11 41.96 46.30 1686 725
2政党 政党の手がかり 議席数 200以上 54.84 1.17 52.55 57.13 1652 730
2政党 政党の手がかり 議席数 50~99 51.61 1.16 49.34 53.88 1585 721
2政党 経済の手がかり 失業率 失業率前期比±0% 52.47 0.81 50.88 54.07 2750 796
2政党 経済の手がかり 失業率 失業率前期比プラス1% 48.08 0.81 46.50 49.67 2741 806
2政党 経済の手がかり 失業率 失業率前期比マイナス1% 49.42 0.83 47.80 51.04 2659 802
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 32.89 0.59 31.73 34.06 4168 841
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 33.95 0.60 32.77 35.12 4277 842
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 33.14 0.61 31.95 34.33 4200 839
3政党 経済の手がかり GDP成長率 GDP成長率±0% 31.77 0.56 30.68 32.85 4297 842
3政党 経済の手がかり GDP成長率 GDP成長率プラス1% 39.75 0.66 38.46 41.05 4075 839
3政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 28.79 0.61 27.60 29.97 4273 843
3政党 政党の手がかり 与野党地位 与党 35.46 0.74 34.01 36.92 4162 842
3政党 政党の手がかり 与野党地位 野党 32.29 0.36 31.58 33.00 8483 843
3政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 38.95 0.63 37.71 40.19 4177 842
3政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 28.55 0.62 27.33 29.77 4284 842
3政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 32.62 0.61 31.43 33.82 4184 843
3政党 政党の手がかり 政策位置 中道 38.05 0.71 36.65 39.45 4113 841
3政党 政党の手がかり 政策位置 右派・保守的 33.14 0.72 31.73 34.55 4306 841
3政党 政党の手がかり 政策位置 左派・革新的 28.94 0.72 27.52 30.36 4226 841
3政党 政党の手がかり 議席数 100~199 38.67 1.01 36.70 40.64 2105 793
3政党 政党の手がかり 議席数 10~49 30.41 0.79 28.86 31.95 2802 826
3政党 政党の手がかり 議席数 10以下 26.84 0.84 25.20 28.49 2794 828
3政党 政党の手がかり 議席数 200以上 38.06 1.03 36.05 40.07 2157 796
3政党 政党の手がかり 議席数 50~99 35.09 0.81 33.49 36.69 2787 825
3政党 経済の手がかり 失業率 失業率前期比±0% 35.07 0.61 33.88 36.27 4268 842
3政党 経済の手がかり 失業率 失業率前期比プラス1% 31.85 0.64 30.58 33.11 4167 839
3政党 経済の手がかり 失業率 失業率前期比マイナス1% 33.04 0.64 31.79 34.29 4210 839
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 24.15 0.47 23.23 25.06 6009 882
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 26.61 0.48 25.68 27.55 5824 882
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 24.26 0.48 23.33 25.20 5807 882
4政党 経済の手がかり GDP成長率 GDP成長率±0% 23.80 0.47 22.89 24.72 5894 881
4政党 経済の手がかり GDP成長率 GDP成長率プラス1% 31.10 0.55 30.03 32.18 5858 882
4政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 20.13 0.48 19.18 21.07 5888 882
4政党 政党の手がかり 与野党地位 与党 28.30 0.72 26.88 29.71 4322 878
4政党 政党の手がかり 与野党地位 野党 23.93 0.23 23.47 24.39 13318 882
4政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 28.93 0.53 27.89 29.97 5814 881
4政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 20.62 0.47 19.70 21.54 5931 882
4政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 25.53 0.47 24.61 26.45 5895 881
4政党 政党の手がかり 政策位置 中道 29.38 0.57 28.26 30.49 5913 882
4政党 政党の手がかり 政策位置 右派・保守的 24.23 0.60 23.06 25.40 5757 882
4政党 政党の手がかり 政策位置 左派・革新的 21.41 0.58 20.28 22.54 5970 882
4政党 政党の手がかり 議席数 100~199 29.83 0.80 28.27 31.39 2977 859
4政党 政党の手がかり 議席数 10~49 23.26 0.58 22.11 24.40 4205 879
4政党 政党の手がかり 議席数 10以下 19.49 0.62 18.28 20.70 4058 875
4政党 政党の手がかり 議席数 200以上 29.36 0.99 27.42 31.30 2224 828
4政党 政党の手がかり 議席数 50~99 26.34 0.62 25.12 27.56 4176 879
4政党 経済の手がかり 失業率 失業率前期比±0% 26.30 0.48 25.36 27.25 5889 882
4政党 経済の手がかり 失業率 失業率前期比プラス1% 22.79 0.50 21.81 23.76 5915 882
4政党 経済の手がかり 失業率 失業率前期比マイナス1% 25.93 0.48 24.98 26.87 5836 881
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 20.10 0.40 19.33 20.87 6965 842
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 21.08 0.42 20.26 21.90 6960 842
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 18.85 0.40 18.06 19.64 7125 842
5政党 経済の手がかり GDP成長率 GDP成長率±0% 18.96 0.41 18.17 19.76 7135 842
5政党 経済の手がかり GDP成長率 GDP成長率プラス1% 25.37 0.48 24.44 26.30 6973 842
5政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 15.67 0.42 14.85 16.50 6942 842
5政党 政党の手がかり 与野党地位 与党 24.06 0.70 22.69 25.44 4193 839
5政党 政党の手がかり 与野党地位 野党 18.99 0.17 18.65 19.33 16857 842
5政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 24.07 0.44 23.21 24.93 6996 841
5政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 15.67 0.40 14.89 16.45 6950 842
5政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 20.23 0.39 19.47 20.99 7104 842
5政党 政党の手がかり 政策位置 中道 23.66 0.50 22.68 24.63 7051 842
5政党 政党の手がかり 政策位置 右派・保守的 19.22 0.50 18.23 20.20 6963 842
5政党 政党の手がかり 政策位置 左派・革新的 17.11 0.49 16.15 18.08 7036 842
5政党 政党の手がかり 議席数 100~199 24.93 0.86 23.25 26.62 2615 813
5政党 政党の手がかり 議席数 10~49 19.03 0.44 18.15 19.90 6423 842
5政党 政党の手がかり 議席数 10以下 15.13 0.46 14.24 16.02 6338 842
5政党 政党の手がかり 議席数 200以上 25.36 0.94 23.51 27.21 2157 789
5政党 政党の手がかり 議席数 50~99 23.60 0.67 22.28 24.92 3517 837
5政党 経済の手がかり 失業率 失業率前期比±0% 21.11 0.42 20.29 21.93 6850 842
5政党 経済の手がかり 失業率 失業率前期比プラス1% 17.91 0.42 17.09 18.74 7157 842
5政党 経済の手がかり 失業率 失業率前期比マイナス1% 21.04 0.44 20.18 21.90 7043 841
表D3 <- readr::read_csv(study_csv("study1", "table_attribute_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study1"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D3), format = "html", row.names = FALSE, caption = "表D3:属性重要度")
表D3:属性重要度
条件 手がかり群 属性 水準数 未調整重要度(pp) 選択肢数調整済み重要度(%)
2政党条件 経済の手がかり 消費者物価指数(CPI) 3 0.74 1.49
2政党条件 経済の手がかり GDP成長率 3 6.96 13.93
2政党条件 政党の手がかり 与野党地位 2 4.91 9.82
2政党条件 経済の手がかり 日経平均株価 3 8.09 16.18
2政党条件 政党の手がかり 政策位置 3 5.31 10.61
2政党条件 政党の手がかり 議席数 5 5.66 11.32
2政党条件 経済の手がかり 失業率 3 2.93 5.85
3政党条件 経済の手がかり 消費者物価指数(CPI) 3 0.70 2.11
3政党条件 経済の手がかり GDP成長率 3 7.31 21.94
3政党条件 政党の手がかり 与野党地位 2 3.18 9.53
3政党条件 経済の手がかり 日経平均株価 3 6.94 20.81
3政党条件 政党の手がかり 政策位置 3 6.07 18.22
3政党条件 政党の手がかり 議席数 5 6.26 18.79
3政党条件 経済の手がかり 失業率 3 2.15 6.46
4政党条件 経済の手がかり 消費者物価指数(CPI) 3 1.64 6.58
4政党条件 経済の手がかり GDP成長率 3 7.32 29.27
4政党条件 政党の手がかり 与野党地位 2 4.37 17.47
4政党条件 経済の手がかり 日経平均株価 3 5.54 22.16
4政党条件 政党の手がかり 政策位置 3 5.31 21.25
4政党条件 政党の手がかり 議席数 5 5.36 21.42
4政党条件 経済の手がかり 失業率 3 2.34 9.37
5政党条件 経済の手がかり 消費者物価指数(CPI) 3 1.49 7.43
5政党条件 経済の手がかり GDP成長率 3 6.46 32.32
5政党条件 政党の手がかり 与野党地位 2 5.07 25.37
5政党条件 経済の手がかり 日経平均株価 3 5.60 28.01
5政党条件 政党の手がかり 政策位置 3 4.36 21.81
5政党条件 政党の手がかり 議席数 5 5.27 26.36
5政党条件 経済の手がかり 失業率 3 2.13 10.66
表D4 <- readr::read_csv(study_csv("study1", "table_cue_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", statistic = "指標")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study1"), 指標 = 統計量日本語(指標, "study1"))
knitr::kable(表日本語(表D4), format = "html", row.names = FALSE, caption = "表D4:政党・経済手がかりの重要度と相対比重")
表D4:政党・経済手がかりの重要度と相対比重
条件 指標 単位 推定値 95% CI下限 95% CI上限
2政党条件 政党手がかり:未調整重要度 pp 5.29 4.20 6.51
2政党条件 経済手がかり:未調整重要度 pp 4.68 4.03 5.72
2政党条件 政党手がかり:選択肢数調整済み重要度 % 10.58 8.40 13.02
2政党条件 経済手がかり:選択肢数調整済み重要度 % 9.36 8.06 11.44
2政党条件 政党手がかりの相対比重 % 53.06 44.85 59.61
3政党条件 政党手がかり:未調整重要度 pp 5.17 4.16 6.23
3政党条件 経済手がかり:未調整重要度 pp 4.28 3.73 5.04
3政党条件 政党手がかり:選択肢数調整済み重要度 % 15.51 12.47 18.68
3政党条件 経済手がかり:選択肢数調整済み重要度 % 12.83 11.20 15.11
3政党条件 政党手がかりの相対比重 % 54.73 47.38 60.49
4政党条件 政党手がかり:未調整重要度 pp 5.01 4.22 5.94
4政党条件 経済手がかり:未調整重要度 pp 4.21 3.73 4.84
4政党条件 政党手がかり:選択肢数調整済み重要度 % 20.05 16.88 23.76
4政党条件 経済手がかり:選択肢数調整済み重要度 % 16.84 14.90 19.34
4政党条件 政党手がかりの相対比重 % 54.34 48.53 59.45
5政党条件 政党手がかり:未調整重要度 pp 4.90 4.12 5.76
5政党条件 経済手がかり:未調整重要度 pp 3.92 3.49 4.50
5政党条件 政党手がかり:選択肢数調整済み重要度 % 24.52 20.58 28.81
5政党条件 経済手がかり:選択肢数調整済み重要度 % 19.60 17.47 22.52
5政党条件 政党手がかりの相対比重 % 55.57 49.63 60.52

図6:実験2(2026年)の政党・経済手がかりの重要度と相対比重

図6重要度データ <- study2_env$relative_panel_adjusted_data
図6相対比重データ <- study2_env$relative_panel_b_data
図6パネルA <- study2_env$relative_panel_adjusted
図6パネルB <- study2_env$relative_panel_c
図6 <- (図6パネルA | 図6パネルB) + patchwork::plot_layout(widths = c(1, 1))
図6

表D5 <- readr::read_csv(study_csv("study2", "table_marginal_means.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", level = "水準")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D5), format = "html", row.names = FALSE, caption = "表D5:限界平均")
表D5:限界平均
条件 手がかり群 属性 水準 限界平均(%) クラスタSE(pp) 95% CI下限(%) 95% CI上限(%) プロファイル数 回答者数
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 48.57 0.82 46.95 50.18 2335 696
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 50.74 0.86 49.06 52.43 2355 700
2政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 50.66 0.83 49.04 52.28 2420 699
2政党 経済の手がかり GDP成長率 GDP成長率±0% 48.98 0.90 47.21 50.74 2342 701
2政党 経済の手がかり GDP成長率 GDP成長率プラス1% 57.31 0.90 55.54 59.08 2401 704
2政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 43.60 0.89 41.86 45.34 2367 702
2政党 政党の手がかり 与野党地位 与党 51.78 0.65 50.51 53.05 3623 711
2政党 政党の手がかり 与野党地位 野党 48.15 0.67 46.83 49.47 3487 709
2政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 55.23 0.90 53.47 56.98 2354 697
2政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 43.71 0.92 41.91 45.52 2274 695
2政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 50.81 0.84 49.15 52.46 2482 699
2政党 政党の手がかり 政策位置 中道 53.58 0.89 51.84 55.33 2413 703
2政党 政党の手がかり 政策位置 右派・保守的 51.80 0.98 49.89 53.71 2390 698
2政党 政党の手がかり 政策位置 左派・革新的 44.39 0.99 42.45 46.33 2307 698
2政党 政党の手がかり 議席数 100~199 54.21 1.26 51.75 56.67 1400 622
2政党 政党の手がかり 議席数 10~49 46.04 1.19 43.70 48.38 1351 624
2政党 政党の手がかり 議席数 10以下 45.27 1.20 42.92 47.62 1491 632
2政党 政党の手がかり 議席数 200以上 53.93 1.28 51.42 56.45 1398 634
2政党 政党の手がかり 議席数 50~99 50.68 1.12 48.48 52.88 1470 641
2政党 経済の手がかり 失業率 失業率前期比±0% 52.49 0.88 50.76 54.22 2389 700
2政党 経済の手がかり 失業率 失業率前期比プラス1% 47.90 0.87 46.18 49.61 2353 696
2政党 経済の手がかり 失業率 失業率前期比マイナス1% 49.58 0.87 47.88 51.28 2368 700
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 33.81 0.54 32.75 34.87 5282 1058
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 35.00 0.56 33.91 36.10 5311 1061
3政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 31.20 0.57 30.08 32.32 5337 1061
3政党 経済の手がかり GDP成長率 GDP成長率±0% 33.50 0.52 32.48 34.52 5394 1059
3政党 経済の手がかり GDP成長率 GDP成長率プラス1% 39.44 0.60 38.26 40.62 5210 1061
3政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 27.19 0.55 26.11 28.26 5326 1059
3政党 政党の手がかり 与野党地位 与党 34.20 0.45 33.31 35.09 7947 1062
3政党 政党の手がかり 与野党地位 野党 32.47 0.45 31.59 33.35 7983 1062
3政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 38.36 0.57 37.25 39.48 5336 1060
3政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 28.59 0.55 27.50 29.68 5320 1059
3政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 33.03 0.56 31.94 34.12 5274 1061
3政党 政党の手がかり 政策位置 中道 36.48 0.62 35.26 37.70 5392 1061
3政党 政党の手がかり 政策位置 右派・保守的 36.06 0.72 34.65 37.47 5285 1059
3政党 政党の手がかり 政策位置 左派・革新的 27.36 0.64 26.09 28.62 5253 1056
3政党 政党の手がかり 議席数 100~199 37.71 0.76 36.23 39.19 3246 1031
3政党 政党の手がかり 議席数 10~49 30.52 0.78 28.99 32.04 3149 1016
3政党 政党の手がかり 議席数 10以下 26.93 0.76 25.43 28.43 3201 1028
3政党 政党の手がかり 議席数 200以上 37.11 0.82 35.50 38.71 3207 1027
3政党 政党の手がかり 議席数 50~99 34.31 0.79 32.77 35.85 3127 1019
3政党 経済の手がかり 失業率 失業率前期比±0% 35.23 0.57 34.11 36.34 5212 1059
3政党 経済の手がかり 失業率 失業率前期比プラス1% 30.91 0.55 29.82 31.99 5381 1059
3政党 経済の手がかり 失業率 失業率前期比マイナス1% 33.93 0.56 32.84 35.03 5337 1059
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 24.56 0.43 23.72 25.40 7255 1097
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 26.38 0.44 25.51 27.25 7404 1097
4政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 24.04 0.44 23.18 24.89 7281 1097
4政党 経済の手がかり GDP成長率 GDP成長率±0% 24.42 0.42 23.60 25.24 7281 1097
4政党 経済の手がかり GDP成長率 GDP成長率プラス1% 30.85 0.45 29.96 31.74 7339 1097
4政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 19.71 0.41 18.90 20.53 7320 1097
4政党 政党の手がかり 与野党地位 与党 25.95 0.36 25.23 26.66 11000 1097
4政党 政党の手がかり 与野党地位 野党 24.05 0.37 23.33 24.77 10940 1097
4政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 28.33 0.48 27.40 29.26 7229 1097
4政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 20.81 0.44 19.94 21.67 7185 1097
4政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 25.80 0.42 24.99 26.62 7526 1097
4政党 政党の手がかり 政策位置 中道 27.52 0.53 26.48 28.57 7296 1096
4政党 政党の手がかり 政策位置 右派・保守的 28.59 0.59 27.43 29.74 7259 1097
4政党 政党の手がかり 政策位置 左派・革新的 18.98 0.51 17.98 19.99 7385 1097
4政党 政党の手がかり 議席数 100~199 28.92 0.61 27.73 30.11 4471 1077
4政党 政党の手がかり 議席数 10~49 22.83 0.59 21.68 23.99 4371 1077
4政党 政党の手がかり 議席数 10以下 17.95 0.60 16.79 19.12 4389 1079
4政党 政党の手がかり 議席数 200以上 29.28 0.66 27.99 30.57 4358 1086
4政党 政党の手がかり 議席数 50~99 25.97 0.62 24.75 27.19 4351 1081
4政党 経済の手がかり 失業率 失業率前期比±0% 26.71 0.45 25.83 27.60 7412 1097
4政党 経済の手がかり 失業率 失業率前期比プラス1% 22.57 0.44 21.69 23.44 7228 1097
4政党 経済の手がかり 失業率 失業率前期比マイナス1% 25.67 0.47 24.76 26.58 7300 1097
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 20.07 0.32 19.45 20.69 11075 1322
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 20.33 0.31 19.72 20.95 11011 1322
5政党 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 19.59 0.32 18.97 20.21 10964 1322
5政党 経済の手がかり GDP成長率 GDP成長率±0% 19.23 0.32 18.61 19.86 11038 1322
5政党 経済の手がかり GDP成長率 GDP成長率プラス1% 24.41 0.36 23.70 25.12 10977 1322
5政党 経済の手がかり GDP成長率 GDP成長率マイナス1% 16.38 0.32 15.76 17.01 11035 1322
5政党 政党の手がかり 与野党地位 与党 21.36 0.28 20.82 21.91 16473 1322
5政党 政党の手がかり 与野党地位 野党 18.65 0.28 18.11 19.19 16577 1322
5政党 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 23.67 0.36 22.97 24.37 11056 1322
5政党 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 16.60 0.34 15.94 17.26 11105 1322
5政党 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 19.74 0.32 19.12 20.37 10889 1322
5政党 政党の手がかり 政策位置 中道 21.66 0.42 20.83 22.48 10985 1322
5政党 政党の手がかり 政策位置 右派・保守的 22.72 0.46 21.82 23.62 11128 1322
5政党 政党の手がかり 政策位置 左派・革新的 15.57 0.41 14.77 16.37 10937 1322
5政党 政党の手がかり 議席数 100~199 23.74 0.49 22.77 24.70 6589 1316
5政党 政党の手がかり 議席数 10~49 16.37 0.42 15.54 17.19 6697 1317
5政党 政党の手がかり 議席数 10以下 14.15 0.44 13.29 15.01 6550 1316
5政党 政党の手がかり 議席数 200以上 24.75 0.52 23.72 25.77 6611 1318
5政党 政党の手がかり 議席数 50~99 21.01 0.48 20.07 21.94 6603 1321
5政党 経済の手がかり 失業率 失業率前期比±0% 20.78 0.33 20.14 21.42 11191 1322
5政党 経済の手がかり 失業率 失業率前期比プラス1% 18.57 0.33 17.92 19.22 10916 1322
5政党 経済の手がかり 失業率 失業率前期比マイナス1% 20.63 0.36 19.93 21.32 10943 1322
表D6 <- readr::read_csv(study_csv("study2", "table_attribute_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D6), format = "html", row.names = FALSE, caption = "表D6:属性重要度")
表D6:属性重要度
条件 手がかり群 属性 水準数 未調整重要度(pp) 選択肢数調整済み重要度(%)
2政党条件 経済の手がかり 消費者物価指数(CPI) 3 1.45 2.90
2政党条件 経済の手がかり GDP成長率 3 9.14 18.28
2政党条件 政党の手がかり 与野党地位 2 3.63 7.26
2政党条件 経済の手がかり 日経平均株価 3 7.68 15.35
2政党条件 政党の手がかり 政策位置 3 6.13 12.26
2政党条件 政党の手がかり 議席数 5 5.16 10.31
2政党条件 経済の手がかり 失業率 3 3.06 6.13
3政党条件 経済の手がかり 消費者物価指数(CPI) 3 2.54 7.61
3政党条件 経済の手がかり GDP成長率 3 8.17 24.51
3政党条件 政党の手がかり 与野党地位 2 1.73 5.20
3政党条件 経済の手がかり 日経平均株価 3 6.51 19.54
3政党条件 政党の手がかり 政策位置 3 6.08 18.25
3政党条件 政党の手がかり 議席数 5 5.63 16.89
3政党条件 経済の手がかり 失業率 3 2.88 8.64
4政党条件 経済の手がかり 消費者物価指数(CPI) 3 1.56 6.25
4政党条件 経済の手がかり GDP成長率 3 7.42 29.70
4政党条件 政党の手がかり 与野党地位 2 1.90 7.58
4政党条件 経済の手がかり 日経平均株価 3 5.02 20.06
4政党条件 政党の手がかり 政策位置 3 6.40 25.60
4政党条件 政党の手がかり 議席数 5 5.75 22.99
4政党条件 経済の手がかり 失業率 3 2.77 11.06
5政党条件 経済の手がかり 消費者物価指数(CPI) 3 0.50 2.48
5政党条件 経済の手がかり GDP成長率 3 5.35 26.74
5政党条件 政党の手がかり 与野党地位 2 2.72 13.58
5政党条件 経済の手がかり 日経平均株価 3 4.72 23.58
5政党条件 政党の手がかり 政策位置 3 4.76 23.82
5政党条件 政党の手がかり 議席数 5 5.71 28.56
5政党条件 経済の手がかり 失業率 3 1.48 7.38
表D7 <- readr::read_csv(study_csv("study2", "table_cue_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", statistic = "指標")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), 指標 = 統計量日本語(指標, "study2"))
knitr::kable(表日本語(表D7), format = "html", row.names = FALSE, caption = "表D7:政党・経済手がかりの重要度と相対比重")
表D7:政党・経済手がかりの重要度と相対比重
条件 指標 単位 推定値 95% CI下限 95% CI上限
2政党条件 政党手がかり:未調整重要度 pp 4.97 3.74 6.35
2政党条件 経済手がかり:未調整重要度 pp 5.33 4.53 6.42
2政党条件 政党手がかり:選択肢数調整済み重要度 % 9.95 7.48 12.70
2政党条件 経済手がかり:選択肢数調整済み重要度 % 10.67 9.06 12.85
2政党条件 政党手がかりの相対比重 % 48.25 39.91 55.66
3政党条件 政党手がかり:未調整重要度 pp 4.48 3.77 5.40
3政党条件 経済手がかり:未調整重要度 pp 5.03 4.39 5.66
3政党条件 政党手がかり:選択肢数調整済み重要度 % 13.44 11.31 16.20
3政党条件 経済手がかり:選択肢数調整済み重要度 % 15.08 13.18 16.99
3政党条件 政党手がかりの相対比重 % 47.14 42.11 53.05
4政党条件 政党手がかり:未調整重要度 pp 4.68 3.98 5.46
4政党条件 経済手がかり:未調整重要度 pp 4.19 3.72 4.76
4政党条件 政党手がかり:選択肢数調整済み重要度 % 18.73 15.93 21.84
4政党条件 経済手がかり:選択肢数調整済み重要度 % 16.77 14.90 19.06
4政党条件 政党手がかりの相対比重 % 52.76 47.46 57.72
5政党条件 政党手がかり:未調整重要度 pp 4.40 3.86 4.98
5政党条件 経済手がかり:未調整重要度 pp 3.01 2.70 3.45
5政党条件 政党手がかり:選択肢数調整済み重要度 % 21.99 19.31 24.88
5政党条件 経済手がかり:選択肢数調整済み重要度 % 15.04 13.50 17.26
5政党条件 政党手がかりの相対比重 % 59.37 54.43 63.34

図7:実験3(2026年)の共変量調整済みAMCE

図7データ <- study3_env$amce_plot_cov
図7 <- ggplot2::ggplot(
  図7データ,
  ggplot2::aes(x = estimate_pp, y = label, shape = party_n, linetype = party_n, group = party_n)
) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.45, color = "grey35") +
  ggplot2::geom_errorbarh(
    ggplot2::aes(xmin = conf.low_pp, xmax = conf.high_pp),
    position = ggplot2::position_dodge(width = 0.65), height = 0.16, linewidth = 0.55
  ) +
  ggplot2::geom_point(position = ggplot2::position_dodge(width = 0.65), size = 2.5, fill = "white", stroke = 0.8) +
  ggplot2::facet_grid(attribute ~ ., scales = "free_y", space = "free_y", switch = "y") +
  ggplot2::scale_shape_manual(values = c("2選択肢" = 16, "3選択肢" = 17, "4選択肢" = 15, "5選択肢" = 1)) +
  ggplot2::scale_linetype_manual(values = c("2選択肢" = "solid", "3選択肢" = "dashed", "4選択肢" = "dotted", "5選択肢" = "dotdash")) +
  ggplot2::labs(x = "選択確率の変化", y = NULL, shape = "選択肢数", linetype = "選択肢数") +
  ggplot2::theme_bw(base_size = 12) +
  ggplot2::theme(legend.position = "top", panel.grid.major.y = ggplot2::element_blank(), panel.grid.minor = ggplot2::element_blank())
図7

表D8 <- readr::read_csv(study_csv("study3", "table_amce_covariate_adjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表D8), format = "html", row.names = FALSE, caption = "表D8:図7に対応する共変量調整済みAMCE")
表D8:図7に対応する共変量調整済みAMCE
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2選択肢条件 政権与党の政党名 立憲民主党 -8.88 3.12 -15.00 -2.76 .005 716
2選択肢条件 政権与党の政党名 日本維新の会 -5.97 2.78 -11.42 -0.53 .032 716
2選択肢条件 政権与党の政党名 公明党 -23.60 2.91 -29.30 -17.89 < .001 716
2選択肢条件 政権与党の政党名 国民民主党 -1.29 2.81 -6.80 4.21 .645 716
2選択肢条件 政権与党の政党名 れいわ新選組 -28.42 3.04 -34.39 -22.45 < .001 716
2選択肢条件 政権与党の政党名 参政党 -14.98 2.78 -20.42 -9.53 < .001 716
2選択肢条件 政権与党の政党名 日本共産党 -33.71 2.91 -39.41 -28.01 < .001 716
2選択肢条件 政権与党の政党名 中道改革連合 -12.57 2.92 -18.30 -6.84 < .001 716
2選択肢条件 政権与党の政党名 チームみらい -5.19 2.82 -10.72 0.34 .066 716
2選択肢条件 GDP成長率 GDP:プラス1% 7.64 1.44 4.82 10.46 < .001 716
2選択肢条件 GDP成長率 GDP:マイナス1% -5.92 1.44 -8.75 -3.09 < .001 716
2選択肢条件 日経平均 日経平均:プラス1000円 2.84 1.42 0.06 5.62 .046 716
2選択肢条件 日経平均 日経平均:マイナス1000円 -5.27 1.43 -8.08 -2.46 < .001 716
2選択肢条件 CPI CPI:プラス1ポイント -0.48 1.43 -3.28 2.31 .735 716
2選択肢条件 CPI CPI:マイナス1ポイント -2.25 1.43 -5.06 0.56 .117 716
2選択肢条件 失業率 失業率:プラス1% -6.05 1.43 -8.85 -3.24 < .001 716
2選択肢条件 失業率 失業率:マイナス1% -1.47 1.42 -4.26 1.32 .301 716
3選択肢条件 政権与党の政党名 立憲民主党 -13.89 2.26 -18.32 -9.46 < .001 939
3選択肢条件 政権与党の政党名 日本維新の会 -9.02 2.05 -13.04 -4.99 < .001 939
3選択肢条件 政権与党の政党名 公明党 -25.32 2.00 -29.24 -21.39 < .001 939
3選択肢条件 政権与党の政党名 国民民主党 -2.57 2.15 -6.79 1.65 .233 939
3選択肢条件 政権与党の政党名 れいわ新選組 -26.05 2.19 -30.35 -21.76 < .001 939
3選択肢条件 政権与党の政党名 参政党 -12.46 2.16 -16.69 -8.22 < .001 939
3選択肢条件 政権与党の政党名 日本共産党 -28.06 2.16 -32.29 -23.84 < .001 939
3選択肢条件 政権与党の政党名 中道改革連合 -18.38 2.26 -22.81 -13.95 < .001 939
3選択肢条件 政権与党の政党名 チームみらい -8.31 2.16 -12.54 -4.07 < .001 939
3選択肢条件 GDP成長率 GDP:プラス1% 7.10 1.00 5.14 9.06 < .001 939
3選択肢条件 GDP成長率 GDP:マイナス1% -4.80 0.97 -6.71 -2.89 < .001 939
3選択肢条件 日経平均 日経平均:プラス1000円 3.38 1.02 1.37 5.39 .001 939
3選択肢条件 日経平均 日経平均:マイナス1000円 -5.27 0.95 -7.13 -3.42 < .001 939
3選択肢条件 CPI CPI:プラス1ポイント -0.44 0.96 -2.33 1.44 .645 939
3選択肢条件 CPI CPI:マイナス1ポイント -1.38 0.94 -3.22 0.46 .142 939
3選択肢条件 失業率 失業率:プラス1% -4.47 0.96 -6.36 -2.58 < .001 939
3選択肢条件 失業率 失業率:マイナス1% -1.96 0.97 -3.87 -0.05 .044 939
4選択肢条件 政権与党の政党名 立憲民主党 -16.35 1.88 -20.03 -12.66 < .001 1063
4選択肢条件 政権与党の政党名 日本維新の会 -9.35 1.73 -12.74 -5.96 < .001 1063
4選択肢条件 政権与党の政党名 公明党 -24.45 1.67 -27.73 -21.17 < .001 1063
4選択肢条件 政権与党の政党名 国民民主党 -4.97 1.80 -8.50 -1.43 .006 1063
4選択肢条件 政権与党の政党名 れいわ新選組 -25.32 1.76 -28.77 -21.88 < .001 1063
4選択肢条件 政権与党の政党名 参政党 -12.38 1.81 -15.93 -8.83 < .001 1063
4選択肢条件 政権与党の政党名 日本共産党 -25.68 1.80 -29.21 -22.15 < .001 1063
4選択肢条件 政権与党の政党名 中道改革連合 -17.95 1.93 -21.72 -14.17 < .001 1063
4選択肢条件 政権与党の政党名 チームみらい -11.30 1.89 -15.01 -7.59 < .001 1063
4選択肢条件 GDP成長率 GDP:プラス1% 5.04 0.76 3.55 6.53 < .001 1063
4選択肢条件 GDP成長率 GDP:マイナス1% -3.49 0.72 -4.91 -2.08 < .001 1063
4選択肢条件 日経平均 日経平均:プラス1000円 3.87 0.80 2.31 5.43 < .001 1063
4選択肢条件 日経平均 日経平均:マイナス1000円 -3.33 0.72 -4.75 -1.91 < .001 1063
4選択肢条件 CPI CPI:プラス1ポイント 0.54 0.73 -0.89 1.98 .459 1063
4選択肢条件 CPI CPI:マイナス1ポイント -1.26 0.73 -2.70 0.18 .087 1063
4選択肢条件 失業率 失業率:プラス1% -3.73 0.71 -5.12 -2.33 < .001 1063
4選択肢条件 失業率 失業率:マイナス1% -2.02 0.73 -3.45 -0.59 .006 1063
5選択肢条件 政権与党の政党名 立憲民主党 -12.98 1.59 -16.11 -9.86 < .001 1314
5選択肢条件 政権与党の政党名 日本維新の会 -8.62 1.42 -11.41 -5.84 < .001 1314
5選択肢条件 政権与党の政党名 公明党 -21.75 1.38 -24.46 -19.04 < .001 1314
5選択肢条件 政権与党の政党名 国民民主党 -5.06 1.49 -7.99 -2.14 < .001 1314
5選択肢条件 政権与党の政党名 れいわ新選組 -21.60 1.41 -24.38 -18.83 < .001 1314
5選択肢条件 政権与党の政党名 参政党 -13.08 1.49 -16.00 -10.15 < .001 1314
5選択肢条件 政権与党の政党名 日本共産党 -21.88 1.42 -24.66 -19.09 < .001 1314
5選択肢条件 政権与党の政党名 中道改革連合 -16.65 1.50 -19.60 -13.70 < .001 1314
5選択肢条件 政権与党の政党名 チームみらい -12.21 1.51 -15.17 -9.26 < .001 1314
5選択肢条件 GDP成長率 GDP:プラス1% 5.49 0.59 4.33 6.64 < .001 1314
5選択肢条件 GDP成長率 GDP:マイナス1% -2.10 0.52 -3.13 -1.08 < .001 1314
5選択肢条件 日経平均 日経平均:プラス1000円 3.78 0.55 2.70 4.86 < .001 1314
5選択肢条件 日経平均 日経平均:マイナス1000円 -2.15 0.53 -3.19 -1.12 < .001 1314
5選択肢条件 CPI CPI:プラス1ポイント 0.42 0.53 -0.62 1.47 .428 1314
5選択肢条件 CPI CPI:マイナス1ポイント -0.10 0.55 -1.18 0.99 .863 1314
5選択肢条件 失業率 失業率:プラス1% -2.85 0.56 -3.93 -1.76 < .001 1314
5選択肢条件 失業率 失業率:マイナス1% -0.89 0.56 -1.98 0.20 .108 1314

図8:実験3(2026年)の政党名・経済手がかりの重要度と相対比重

図8重要度データ <- study3_env$relative_panel_adjusted_data
図8相対比重データ <- study3_env$relative_panel_b_data
図8パネルA <- study3_env$relative_panel_adjusted
図8パネルB <- study3_env$relative_panel_c
図8 <- (図8パネルA | 図8パネルB) + patchwork::plot_layout(widths = c(1, 1))
図8

表D9 <- readr::read_csv(study_csv("study3", "table_marginal_means.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", level = "水準")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D9), format = "html", row.names = FALSE, caption = "表D9:限界平均")
表D9:限界平均
条件 手がかり群 属性 水準 限界平均(%) クラスタSE(pp) 95% CI下限(%) 95% CI上限(%) プロファイル数 回答者数
2選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 50.82 0.85 49.15 52.48 2387 706
2選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 50.27 0.85 48.62 51.93 2387 697
2選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 48.91 0.86 47.23 50.59 2386 707
2選択肢 経済の手がかり GDP成長率 GDP成長率±0% 49.53 0.85 47.87 51.19 2344 705
2選択肢 経済の手がかり GDP成長率 GDP成長率プラス1% 57.15 0.84 55.50 58.80 2425 708
2選択肢 経済の手がかり GDP成長率 GDP成長率マイナス1% 43.20 0.87 41.51 44.90 2391 701
2選択肢 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 53.29 0.86 51.60 54.98 2357 709
2選択肢 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 45.62 0.85 43.96 47.29 2400 706
2選択肢 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 51.14 0.84 49.50 52.79 2403 707
2選択肢 政党の手がかり 政党名 れいわ新選組 35.36 2.01 31.41 39.30 676 465
2選択肢 政党の手がかり 政党名 チームみらい 58.49 1.93 54.71 62.28 730 475
2選択肢 政党の手がかり 政党名 中道改革連合 50.41 1.90 46.68 54.14 728 471
2選択肢 政党の手がかり 政党名 公明党 39.29 1.95 35.46 43.11 700 479
2選択肢 政党の手がかり 政党名 参政党 48.53 1.95 44.70 52.36 746 512
2選択肢 政党の手がかり 政党名 国民民主党 62.16 1.94 58.37 65.96 703 468
2選択肢 政党の手がかり 政党名 日本共産党 29.52 1.90 25.80 33.24 708 484
2選択肢 政党の手がかり 政党名 日本維新の会 57.49 2.03 53.51 61.47 734 476
2選択肢 政党の手がかり 政党名 立憲民主党 54.44 2.07 50.39 58.49 720 466
2選択肢 政党の手がかり 政党名 自由民主党 62.94 1.94 59.14 66.74 715 481
2選択肢 経済の手がかり 失業率 失業率前期比±0% 52.94 0.83 51.31 54.56 2433 708
2選択肢 経済の手がかり 失業率 失業率前期比プラス1% 46.41 0.84 44.76 48.07 2383 705
2選択肢 経済の手がかり 失業率 失業率前期比マイナス1% 50.60 0.86 48.91 52.29 2344 709
3選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 33.86 0.56 32.77 34.96 4728 937
3選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 33.51 0.57 32.39 34.63 4700 934
3選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 32.62 0.56 31.51 33.72 4657 935
3選択肢 経済の手がかり GDP成長率 GDP成長率±0% 32.55 0.57 31.43 33.66 4704 937
3選択肢 経済の手がかり GDP成長率 GDP成長率プラス1% 39.61 0.61 38.41 40.81 4701 936
3選択肢 経済の手がかり GDP成長率 GDP成長率マイナス1% 27.82 0.59 26.66 28.98 4680 935
3選択肢 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 37.31 0.61 36.11 38.51 4661 938
3選択肢 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 28.75 0.57 27.63 29.86 4679 937
3選択肢 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 33.95 0.58 32.82 35.08 4745 935
3選択肢 政党の手がかり 政党名 れいわ新選組 21.61 1.26 19.15 24.08 1388 808
3選択肢 政党の手がかり 政党名 チームみらい 39.42 1.41 36.65 42.18 1403 779
3選択肢 政党の手がかり 政党名 中道改革連合 29.22 1.36 26.55 31.89 1451 800
3選択肢 政党の手がかり 政党名 公明党 22.58 1.19 20.25 24.90 1382 778
3選択肢 政党の手がかり 政党名 参政党 35.54 1.48 32.63 38.44 1376 776
3選択肢 政党の手がかり 政党名 国民民主党 45.02 1.43 42.21 47.83 1446 791
3選択肢 政党の手がかり 政党名 日本共産党 19.49 1.24 17.06 21.92 1452 782
3選択肢 政党の手がかり 政党名 日本維新の会 38.85 1.48 35.95 41.76 1413 771
3選択肢 政党の手がかり 政党名 立憲民主党 33.87 1.39 31.14 36.59 1376 778
3選択肢 政党の手がかり 政党名 自由民主党 47.78 1.53 44.78 50.79 1398 791
3選択肢 経済の手がかり 失業率 失業率前期比±0% 35.76 0.56 34.67 36.85 4771 936
3選択肢 経済の手がかり 失業率 失業率前期比プラス1% 30.77 0.59 29.61 31.92 4677 936
3選択肢 経済の手がかり 失業率 失業率前期比マイナス1% 33.43 0.60 32.25 34.61 4637 937
4選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 25.18 0.42 24.35 26.01 7180 1062
4選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 25.83 0.46 24.94 26.72 6988 1063
4選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 24.00 0.45 23.11 24.89 7092 1063
4選択肢 経済の手がかり GDP成長率 GDP成長率±0% 24.43 0.43 23.59 25.27 7090 1063
4選択肢 経済の手がかり GDP成長率 GDP成長率プラス1% 29.52 0.46 28.61 30.43 7104 1060
4選択肢 経済の手がかり GDP成長率 GDP成長率マイナス1% 21.03 0.44 20.17 21.89 7066 1063
4選択肢 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 28.78 0.47 27.85 29.71 7057 1063
4選択肢 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 21.55 0.43 20.71 22.39 7206 1063
4選択肢 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 24.74 0.44 23.87 25.61 6997 1063
4選択肢 政党の手がかり 政党名 れいわ新選組 14.42 0.89 12.67 16.16 2164 978
4選択肢 政党の手がかり 政党名 チームみらい 28.40 1.13 26.19 30.62 2144 977
4選択肢 政党の手がかり 政党名 中道改革連合 21.79 1.10 19.64 23.94 2079 970
4選択肢 政党の手がかり 政党名 公明党 15.49 0.90 13.72 17.25 2150 992
4選択肢 政党の手がかり 政党名 参政党 27.28 1.14 25.04 29.52 2126 975
4選択肢 政党の手がかり 政党名 国民民主党 34.80 1.18 32.49 37.11 2115 982
4選択肢 政党の手がかり 政党名 日本共産党 14.24 0.90 12.48 16.00 2184 988
4選択肢 政党の手がかり 政党名 日本維新の会 30.69 1.15 28.44 32.95 2108 987
4選択肢 政党の手がかり 政党名 立憲民主党 23.50 1.07 21.40 25.59 2060 978
4選択肢 政党の手がかり 政党名 自由民主党 39.91 1.34 37.29 42.52 2130 976
4選択肢 経済の手がかり 失業率 失業率前期比±0% 27.07 0.42 26.25 27.89 7067 1063
4選択肢 経済の手がかり 失業率 失業率前期比プラス1% 23.14 0.42 22.31 23.97 7087 1062
4選択肢 経済の手がかり 失業率 失業率前期比マイナス1% 24.80 0.43 23.94 25.65 7106 1062
5選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比±0ポイント 19.78 0.31 19.16 20.39 10978 1314
5選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比プラス1ポイント 20.43 0.32 19.80 21.07 11001 1314
5選択肢 経済の手がかり 消費者物価指数(CPI) CPI前期比マイナス1ポイント 19.79 0.34 19.13 20.45 10871 1314
5選択肢 経済の手がかり GDP成長率 GDP成長率±0% 18.91 0.32 18.29 19.54 10924 1314
5選択肢 経済の手がかり GDP成長率 GDP成長率プラス1% 24.36 0.36 23.64 25.07 10954 1314
5選択肢 経済の手がかり GDP成長率 GDP成長率マイナス1% 16.73 0.33 16.09 17.38 10972 1314
5選択肢 経済の手がかり 日経平均株価 日経平均前月同期比プラス1000円 23.22 0.33 22.57 23.87 11046 1314
5選択肢 経済の手がかり 日経平均株価 日経平均前月同期比マイナス1000円 17.33 0.33 16.69 17.97 10806 1314
5選択肢 経済の手がかり 日経平均株価 日経平均前月同期比変わらず 19.39 0.31 18.78 19.99 10998 1314
5選択肢 政党の手がかり 政党名 れいわ新選組 11.66 0.67 10.34 12.97 3277 1281
5選択肢 政党の手がかり 政党名 チームみらい 21.13 0.87 19.43 22.83 3351 1281
5選択肢 政党の手がかり 政党名 中道改革連合 16.82 0.80 15.26 18.39 3311 1275
5選択肢 政党の手がかり 政党名 公明党 11.63 0.67 10.31 12.94 3243 1262
5選択肢 政党の手がかり 政党名 参政党 20.21 0.89 18.47 21.96 3280 1270
5選択肢 政党の手がかり 政党名 国民民主党 28.33 0.92 26.51 30.14 3315 1274
5選択肢 政党の手がかり 政党名 日本共産党 11.49 0.67 10.18 12.81 3271 1276
5選択肢 政党の手がかり 政党名 日本維新の会 24.77 0.93 22.93 26.60 3218 1275
5選択肢 政党の手がかり 政党名 立憲民主党 20.46 0.88 18.73 22.18 3290 1277
5選択肢 政党の手がかり 政党名 自由民主党 33.33 1.11 31.16 35.51 3294 1278
5選択肢 経済の手がかり 失業率 失業率前期比±0% 21.24 0.32 20.60 21.88 10965 1314
5選択肢 経済の手がかり 失業率 失業率前期比プラス1% 18.51 0.33 17.86 19.16 10768 1313
5選択肢 経済の手がかり 失業率 失業率前期比マイナス1% 20.22 0.32 19.59 20.85 11117 1314
表D10 <- readr::read_csv(study_csv("study3", "table_attribute_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), 属性 = 属性日本語(属性))
knitr::kable(表日本語(表D10), format = "html", row.names = FALSE, caption = "表D10:属性重要度")
表D10:属性重要度
条件 手がかり群 属性 水準数 未調整重要度(pp) 選択肢数調整済み重要度(%)
2選択肢条件 経済の手がかり 消費者物価指数(CPI) 3 1.27 2.54
2選択肢条件 経済の手がかり GDP成長率 3 9.30 18.60
2選択肢条件 経済の手がかり 日経平均株価 3 5.11 10.22
2選択肢条件 政党の手がかり 政党名 10 13.68 27.35
2選択肢条件 経済の手がかり 失業率 3 4.35 8.70
3選択肢条件 経済の手がかり 消費者物価指数(CPI) 3 0.83 2.49
3選択肢条件 経済の手がかり GDP成長率 3 7.86 23.58
3選択肢条件 経済の手がかり 日経平均株価 3 5.71 17.13
3選択肢条件 政党の手がかり 政党名 10 11.85 35.55
3選択肢条件 経済の手がかり 失業率 3 3.33 9.98
4選択肢条件 経済の手がかり 消費者物価指数(CPI) 3 1.22 4.88
4選択肢条件 経済の手がかり GDP成長率 3 5.66 22.64
4選択肢条件 経済の手がかり 日経平均株価 3 4.82 19.28
4選択肢条件 政党の手がかり 政党名 10 10.52 42.07
4選択肢条件 経済の手がかり 失業率 3 2.62 10.48
5選択肢条件 経済の手がかり 消費者物価指数(CPI) 3 0.44 2.20
5選択肢条件 経済の手がかり GDP成長率 3 5.08 25.41
5選択肢条件 経済の手がかり 日経平均株価 3 3.93 19.63
5選択肢条件 政党の手がかり 政党名 10 8.71 43.57
5選択肢条件 経済の手がかり 失業率 3 1.82 9.11
表D11 <- readr::read_csv(study_csv("study3", "table_cue_importance.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", statistic = "指標")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), 指標 = 統計量日本語(指標, "study3"))
knitr::kable(表日本語(表D11), format = "html", row.names = FALSE, caption = "表D11:政党名・経済手がかりの重要度と相対比重")
表D11:政党名・経済手がかりの重要度と相対比重
条件 指標 単位 推定値 95% CI下限 95% CI上限
2選択肢条件 政党手がかり:未調整重要度 pp 13.68 12.04 15.55
2選択肢条件 経済手がかり:未調整重要度 pp 5.01 4.18 6.05
2選択肢条件 政党手がかり:選択肢数調整済み重要度 % 27.35 24.08 31.09
2選択肢条件 経済手がかり:選択肢数調整済み重要度 % 10.02 8.36 12.09
2選択肢条件 政党手がかりの相対比重 % 73.20 68.24 77.40
3選択肢条件 政党手がかり:未調整重要度 pp 11.85 10.54 13.20
3選択肢条件 経済手がかり:未調整重要度 pp 4.43 3.85 5.10
3選択肢条件 政党手がかり:選択肢数調整済み重要度 % 35.55 31.61 39.59
3選択肢条件 経済手がかり:選択肢数調整済み重要度 % 13.29 11.55 15.31
3選択肢条件 政党手がかりの相対比重 % 72.78 68.90 76.46
4選択肢条件 政党手がかり:未調整重要度 pp 10.52 9.54 11.69
4選択肢条件 経済手がかり:未調整重要度 pp 3.58 3.05 4.09
4選択肢条件 政党手がかり:選択肢数調整済み重要度 % 42.07 38.15 46.76
4選択肢条件 経済手がかり:選択肢数調整済み重要度 % 14.32 12.21 16.37
4選択肢条件 政党手がかりの相対比重 % 74.61 71.03 78.20
5選択肢条件 政党手がかり:未調整重要度 pp 8.71 8.04 9.57
5選択肢条件 経済手がかり:未調整重要度 pp 2.82 2.46 3.26
5選択肢条件 政党手がかり:選択肢数調整済み重要度 % 43.57 40.22 47.87
5選択肢条件 経済手がかり:選択肢数調整済み重要度 % 14.08 12.31 16.30
5選択肢条件 政党手がかりの相対比重 % 75.57 72.24 78.63

図9:実験3(2026年)の支持政党と提示政党名の一致効果

図9 <- study3_env$p_party_match
図9

表D12元 <- readr::read_csv(study_csv("study3", "table_party_match.csv"), show_col_types = FALSE)

表D12条件列 <- intersect(c("選択肢数", "条件", "party_n"), names(表D12元))
if (length(表D12条件列) == 0) stop("Check condition column")
表D12条件列 <- 表D12条件列[[1]]

if (!"回答者数" %in% names(表D12元)) {
  表D12元$回答者数 <- NA_character_
}

実験3条件人数 <- study3_env$conjoint_all_m %>%
  dplyr::distinct(ID, party_n) %>%
  dplyr::count(party_n, name = "回答者数補完")

表D12 <- 表D12元 %>%
  dplyr::mutate(条件数 = 数値列(.data[[表D12条件列]])) %>%
  dplyr::select(-dplyr::all_of(表D12条件列)) %>%
  dplyr::left_join(実験3条件人数, by = c("条件数" = "party_n")) %>%
  dplyr::mutate(
    回答者数 = dplyr::coalesce(数値列(回答者数), 回答者数補完),
    条件 = 条件日本語(条件数, "study3")
  ) %>%
  dplyr::select(-条件数, -回答者数補完) %>%
  dplyr::relocate(条件, .after = 対象)

knitr::kable(
  表日本語(表D12),
  format = "html",
  row.names = FALSE,
  caption = "表D12:支持政党と提示政党名の一致効果"
)
表D12:支持政党と提示政党名の一致効果
対象 条件 一致効果(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
全体 2選択肢条件 28.82 2.86 23.21 34.43 < .001 716
全体 3選択肢条件 38.91 2.17 34.66 43.16 < .001 939
全体 4選択肢条件 44.35 1.99 40.44 48.25 < .001 1063
全体 5選択肢条件 44.83 1.82 41.25 48.41 < .001 1314
自民党支持者 2選択肢条件 34.77 3.43 28.06 41.49 < .001 163
自民党支持者 3選択肢条件 42.74 3.13 36.61 48.87 < .001 219
自民党支持者 4選択肢条件 47.62 2.88 41.97 53.28 < .001 254
自民党支持者 5選択肢条件 49.55 2.70 44.26 54.84 < .001 311
中道改革支持者 2選択肢条件 27.10 13.17 1.30 52.91 .052 23
中道改革支持者 3選択肢条件 35.16 9.34 16.85 53.48 .001 23
中道改革支持者 4選択肢条件 36.97 7.47 22.33 51.60 < .001 34
中道改革支持者 5選択肢条件 46.37 7.16 32.33 60.40 < .001 40
立憲支持者 2選択肢条件 18.12 12.01 -5.41 41.66 .144 26
立憲支持者 3選択肢条件 46.89 7.00 33.16 60.61 < .001 38
立憲支持者 4選択肢条件 41.34 5.79 30.00 52.69 < .001 37
立憲支持者 5選択肢条件 40.03 6.09 28.09 51.97 < .001 63
参政党支持者 2選択肢条件 39.23 7.32 24.88 53.59 < .001 30
参政党支持者 3選択肢条件 53.61 6.14 41.57 65.65 < .001 46
参政党支持者 4選択肢条件 62.99 5.48 52.25 73.72 < .001 42
参政党支持者 5選択肢条件 61.03 5.53 50.20 71.86 < .001 52

E. 実験1(2023年)の補足分析

補図E1:共変量を含めないAMCE

補図E1データ <- study1_env$amce_plot_df_nocov_facet
補図E1 <- study1_env$p_amce_facet_nocov
補図E1

表E1 <- readr::read_csv(study_csv("study1", "table_amce_unadjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表E1), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2政党条件 政策位置 右派・保守的 -2.50 1.44 -5.32 0.32 .082 815
2政党条件 政策位置 左派・革新的 -8.04 1.43 -10.85 -5.23 < .001 815
2政党条件 与党/野党 与党 4.77 1.21 2.40 7.14 < .001 815
2政党条件 GDP成長率 GDP:プラス1% 7.72 1.40 4.99 10.46 < .001 815
2政党条件 GDP成長率 GDP:マイナス1% -2.74 1.37 -5.44 -0.05 .046 815
2政党条件 日経平均 日経平均:プラス1000円 6.33 1.39 3.62 9.05 < .001 815
2政党条件 日経平均 日経平均:マイナス1000円 -5.45 1.34 -8.08 -2.82 < .001 815
2政党条件 議席数 議席数:10~49 2.14 1.74 -1.26 5.55 .218 815
2政党条件 議席数 議席数:50~99 7.52 1.76 4.08 10.97 < .001 815
2政党条件 議席数 議席数:100~199 8.89 1.78 5.40 12.39 < .001 815
2政党条件 議席数 議席数:200以上 10.72 1.83 7.12 14.31 < .001 815
2政党条件 CPI CPI:プラス1ポイント -0.14 1.38 -2.85 2.56 .918 815
2政党条件 CPI CPI:マイナス1ポイント -1.13 1.38 -3.83 1.56 .410 815
2政党条件 失業率 失業率:プラス1% -4.50 1.38 -7.21 -1.79 .001 815
2政党条件 失業率 失業率:マイナス1% -2.82 1.39 -5.54 -0.10 .042 815
3政党条件 政策位置 右派・保守的 -4.78 1.22 -7.17 -2.40 < .001 843
3政党条件 政策位置 左派・革新的 -8.99 1.22 -11.39 -6.59 < .001 843
3政党条件 与党/野党 与党 3.50 1.10 1.35 5.65 .001 843
3政党条件 GDP成長率 GDP:プラス1% 8.04 1.02 6.04 10.05 < .001 843
3政党条件 GDP成長率 GDP:マイナス1% -2.67 0.96 -4.55 -0.80 .005 843
3政党条件 日経平均 日経平均:プラス1000円 6.05 1.06 3.99 8.12 < .001 843
3政党条件 日経平均 日経平均:マイナス1000円 -4.23 1.04 -6.27 -2.19 < .001 843
3政党条件 議席数 議席数:10~49 3.67 1.24 1.24 6.09 .003 843
3政党条件 議席数 議席数:50~99 8.36 1.28 5.86 10.86 < .001 843
3政党条件 議席数 議席数:100~199 11.70 1.48 8.79 14.60 < .001 843
3政党条件 議席数 議席数:200以上 11.27 1.52 8.29 14.25 < .001 843
3政党条件 CPI CPI:プラス1ポイント 1.16 1.01 -0.82 3.13 .252 843
3政党条件 CPI CPI:マイナス1ポイント 0.15 1.01 -1.83 2.12 .885 843
3政党条件 失業率 失業率:プラス1% -3.40 1.05 -5.47 -1.34 .001 843
3政党条件 失業率 失業率:マイナス1% -2.05 1.06 -4.12 0.03 .054 843
4政党条件 政策位置 右派・保守的 -5.27 0.99 -7.22 -3.32 < .001 882
4政党条件 政策位置 左派・革新的 -8.27 0.99 -10.21 -6.33 < .001 882
4政党条件 与党/野党 与党 4.26 0.95 2.40 6.13 < .001 882
4政党条件 GDP成長率 GDP:プラス1% 7.38 0.88 5.66 9.11 < .001 882
4政党条件 GDP成長率 GDP:マイナス1% -3.46 0.78 -4.98 -1.94 < .001 882
4政党条件 日経平均 日経平均:プラス1000円 3.24 0.86 1.55 4.93 < .001 882
4政党条件 日経平均 日経平均:マイナス1000円 -5.21 0.77 -6.71 -3.71 < .001 882
4政党条件 議席数 議席数:10~49 3.79 0.89 2.05 5.53 < .001 882
4政党条件 議席数 議席数:50~99 6.68 0.99 4.74 8.62 < .001 882
4政党条件 議席数 議席数:100~199 10.16 1.14 7.93 12.40 < .001 882
4政党条件 議席数 議席数:200以上 9.90 1.30 7.35 12.45 < .001 882
4政党条件 CPI CPI:プラス1ポイント 2.79 0.81 1.21 4.38 < .001 882
4政党条件 CPI CPI:マイナス1ポイント 0.05 0.80 -1.53 1.63 .952 882
4政党条件 失業率 失業率:プラス1% -3.58 0.84 -5.23 -1.94 < .001 882
4政党条件 失業率 失業率:マイナス1% -0.45 0.82 -2.05 1.16 .586 882
5政党条件 政策位置 右派・保守的 -4.37 0.85 -6.04 -2.70 < .001 842
5政党条件 政策位置 左派・革新的 -6.56 0.85 -8.23 -4.89 < .001 842
5政党条件 与党/野党 与党 4.94 0.87 3.23 6.65 < .001 842
5政党条件 GDP成長率 GDP:プラス1% 6.41 0.77 4.91 7.92 < .001 842
5政党条件 GDP成長率 GDP:マイナス1% -3.27 0.67 -4.59 -1.95 < .001 842
5政党条件 日経平均 日経平均:プラス1000円 3.79 0.72 2.38 5.19 < .001 842
5政党条件 日経平均 日経平均:マイナス1000円 -4.52 0.65 -5.79 -3.25 < .001 842
5政党条件 議席数 議席数:10~49 3.79 0.71 2.41 5.18 < .001 842
5政党条件 議席数 議席数:50~99 8.21 0.93 6.39 10.03 < .001 842
5政党条件 議席数 議席数:100~199 9.80 1.09 7.67 11.93 < .001 842
5政党条件 議席数 議席数:200以上 10.12 1.14 7.89 12.35 < .001 842
5政党条件 CPI CPI:プラス1ポイント 0.89 0.68 -0.45 2.23 .195 842
5政党条件 CPI CPI:マイナス1ポイント -1.16 0.67 -2.47 0.16 .087 842
5政党条件 失業率 失業率:プラス1% -2.97 0.71 -4.36 -1.59 < .001 842
5政党条件 失業率 失業率:マイナス1% -0.07 0.72 -1.47 1.34 .927 842

補図E2:2政党条件との差

補図E2データ <- study1_env$interaction_plot_df
補図E2 <- study1_env$p_interaction
補図E2

表E2 <- readr::read_csv(study_csv("study1", "table_amce_interaction.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, attribute = "属性")) %>%
  dplyr::mutate(dplyr::across(dplyr::any_of("属性"), 属性日本語))
knitr::kable(表日本語(表E2), format = "html", row.names = FALSE)
比較条件 属性 水準 2選択肢条件との差(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値
3政党 政策位置 右派・保守的 -2.28 1.88 -5.97 1.41 0.226
4政党 政策位置 右派・保守的 -2.77 1.75 -6.19 0.66 0.114
5政党 政策位置 右派・保守的 -1.87 1.67 -5.14 1.41 0.264
3政党 政策位置 左派・革新的 -0.95 1.88 -4.64 2.74 0.613
4政党 政策位置 左派・革新的 -0.23 1.74 -3.64 3.18 0.893
5政党 政策位置 左派・革新的 1.48 1.66 -1.78 4.74 0.374
3政党 与党/野党 与党 -1.27 1.63 -4.47 1.92 0.435
4政党 与党/野党 与党 -0.51 1.54 -3.52 2.50 0.740
5政党 与党/野党 与党 0.17 1.49 -2.75 3.09 0.910
3政党 GDP成長率 GDP:プラス1% 0.32 1.73 -3.07 3.71 0.852
4政党 GDP成長率 GDP:プラス1% -0.34 1.65 -3.57 2.89 0.838
5政党 GDP成長率 GDP:プラス1% -1.31 1.59 -4.43 1.81 0.412
3政党 GDP成長率 GDP:マイナス1% 0.07 1.67 -3.21 3.35 0.967
4政党 GDP成長率 GDP:マイナス1% -0.72 1.58 -3.81 2.38 0.650
5政党 GDP成長率 GDP:マイナス1% -0.53 1.53 -3.53 2.47 0.730
3政党 日経平均 日経平均:プラス1000円 -0.28 1.74 -3.69 3.13 0.873
4政党 日経平均 日経平均:プラス1000円 -3.10 1.63 -6.29 0.10 0.058
5政党 日経平均 日経平均:プラス1000円 -2.55 1.56 -5.60 0.51 0.102
3政党 日経平均 日経平均:マイナス1000円 1.22 1.70 -2.10 4.55 0.471
4政党 日経平均 日経平均:マイナス1000円 0.24 1.54 -2.78 3.27 0.875
5政党 日経平均 日経平均:マイナス1000円 0.93 1.49 -1.99 3.85 0.532
3政党 議席数 議席数:10~49 1.52 2.13 -2.66 5.70 0.475
4政党 議席数 議席数:10~49 1.65 1.95 -2.18 5.47 0.398
5政党 議席数 議席数:10~49 1.65 1.87 -2.02 5.33 0.379
3政党 議席数 議席数:50~99 0.84 2.17 -3.42 5.09 0.700
4政党 議席数 議席数:50~99 -0.84 2.02 -4.80 3.11 0.676
5政党 議席数 議席数:50~99 0.69 1.99 -3.21 4.58 0.729
3政党 議席数 議席数:100~199 2.80 2.32 -1.74 7.35 0.226
4政党 議席数 議席数:100~199 1.27 2.12 -2.87 5.42 0.548
5政党 議席数 議席数:100~199 0.91 2.09 -3.18 4.99 0.664
3政党 議席数 議席数:200以上 0.55 2.38 -4.12 5.22 0.817
4政党 議席数 議席数:200以上 -0.82 2.25 -5.22 3.59 0.717
5政党 議席数 議席数:200以上 -0.60 2.16 -4.82 3.63 0.781
3政党 CPI CPI:プラス1ポイント 1.30 1.71 -2.05 4.65 0.447
4政党 CPI CPI:プラス1ポイント 2.93 1.60 -0.20 6.07 0.066
5政党 CPI CPI:プラス1ポイント 1.03 1.54 -1.99 4.05 0.504
3政党 CPI CPI:マイナス1ポイント 1.28 1.70 -2.06 4.62 0.453
4政党 CPI CPI:マイナス1ポイント 1.18 1.59 -1.94 4.30 0.458
5政党 CPI CPI:マイナス1ポイント -0.02 1.53 -3.02 2.98 0.988
3政党 失業率 失業率:プラス1% 1.10 1.74 -2.30 4.50 0.527
4政党 失業率 失業率:プラス1% 0.92 1.62 -2.25 4.08 0.571
5政党 失業率 失業率:プラス1% 1.53 1.55 -1.52 4.57 0.325
3政党 失業率 失業率:マイナス1% 0.78 1.74 -2.64 4.19 0.657
4政党 失業率 失業率:マイナス1% 2.37 1.61 -0.78 5.53 0.141
5政党 失業率 失業率:マイナス1% 2.76 1.56 -0.31 5.82 0.078

補図E3:条件付きロジット

補図E3 <- study1_env$p_clogit_or
補図E3

表E3 <- readr::read_csv(study_csv("study1", "table_conditional_logit.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", label = "水準")) %>%
  dplyr::mutate(
    条件 = 条件日本語(条件, "study1"),
    属性 = 属性日本語(属性)
  ) %>%
  dplyr::select(-dplyr::any_of(c("term", "variable", "policy_position", "government_status")))
knitr::kable(表日本語(表E3), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) log係数 標準誤差 オッズ比 95% CI下限(OR) 95% CI上限(OR) p値
2政党 政策位置 右派・保守的 -0.115 0.060 0.891 0.792 1.003 .055
2政党 政策位置 左派・革新的 -0.350 0.060 0.705 0.627 0.793 < .001
2政党 与党/野党 与党 0.207 0.051 1.229 1.112 1.359 < .001
2政党 GDP成長率 GDP:プラス1% 0.309 0.058 1.362 1.215 1.526 < .001
2政党 GDP成長率 GDP:マイナス1% -0.133 0.058 0.876 0.782 0.980 .021
2政党 日経平均 日経平均:プラス1000円 0.261 0.059 1.298 1.156 1.457 < .001
2政党 日経平均 日経平均:マイナス1000円 -0.246 0.058 0.782 0.698 0.876 < .001
2政党 議席数 議席数:10~49 0.112 0.074 1.118 0.968 1.291 .130
2政党 議席数 議席数:50~99 0.331 0.074 1.392 1.205 1.608 < .001
2政党 議席数 議席数:100~199 0.378 0.077 1.459 1.255 1.696 < .001
2政党 議席数 議席数:200以上 0.442 0.077 1.555 1.337 1.810 < .001
2政党 CPI CPI:プラス1ポイント 0.020 0.057 1.020 0.911 1.142 .728
2政党 CPI CPI:マイナス1ポイント -0.047 0.058 0.954 0.852 1.068 .414
2政党 失業率 失業率:プラス1% -0.201 0.059 0.818 0.728 0.918 < .001
2政党 失業率 失業率:マイナス1% -0.136 0.058 0.873 0.779 0.978 .019
3政党 政策位置 右派・保守的 -0.225 0.056 0.798 0.716 0.891 < .001
3政党 政策位置 左派・革新的 -0.435 0.059 0.647 0.576 0.726 < .001
3政党 与党/野党 与党 0.177 0.051 1.193 1.080 1.318 < .001
3政党 GDP成長率 GDP:プラス1% 0.373 0.047 1.451 1.323 1.592 < .001
3政党 GDP成長率 GDP:マイナス1% -0.136 0.048 0.872 0.794 0.959 .005
3政党 日経平均 日経平均:プラス1000円 0.283 0.049 1.328 1.207 1.460 < .001
3政党 日経平均 日経平均:マイナス1000円 -0.201 0.051 0.818 0.741 0.903 < .001
3政党 議席数 議席数:10~49 0.197 0.063 1.218 1.076 1.379 .002
3政党 議席数 議席数:50~99 0.410 0.063 1.506 1.330 1.706 < .001
3政党 議席数 議席数:100~199 0.574 0.072 1.776 1.542 2.045 < .001
3政党 議席数 議席数:200以上 0.544 0.073 1.723 1.492 1.989 < .001
3政党 CPI CPI:プラス1ポイント 0.053 0.048 1.054 0.959 1.159 .273
3政党 CPI CPI:マイナス1ポイント -0.001 0.047 0.999 0.911 1.096 .989
3政党 失業率 失業率:プラス1% -0.167 0.049 0.846 0.768 0.932 < .001
3政党 失業率 失業率:マイナス1% -0.103 0.049 0.902 0.819 0.994 .037
4政党 政策位置 右派・保守的 -0.286 0.054 0.752 0.676 0.835 < .001
4政党 政策位置 左派・革新的 -0.468 0.057 0.626 0.560 0.700 < .001
4政党 与党/野党 与党 0.241 0.051 1.273 1.153 1.405 < .001
4政党 GDP成長率 GDP:プラス1% 0.384 0.046 1.468 1.342 1.605 < .001
4政党 GDP成長率 GDP:マイナス1% -0.207 0.047 0.813 0.741 0.891 < .001
4政党 日経平均 日経平均:プラス1000円 0.168 0.045 1.183 1.083 1.293 < .001
4政党 日経平均 日経平均:マイナス1000円 -0.301 0.045 0.740 0.677 0.809 < .001
4政党 議席数 議席数:10~49 0.232 0.056 1.261 1.130 1.406 < .001
4政党 議席数 議席数:50~99 0.399 0.060 1.491 1.326 1.676 < .001
4政党 議席数 議席数:100~199 0.585 0.065 1.795 1.579 2.040 < .001
4政党 議席数 議席数:200以上 0.567 0.073 1.762 1.527 2.033 < .001
4政党 CPI CPI:プラス1ポイント 0.150 0.045 1.161 1.063 1.269 < .001
4政党 CPI CPI:マイナス1ポイント -0.001 0.046 0.999 0.912 1.094 .983
4政党 失業率 失業率:プラス1% -0.204 0.048 0.815 0.742 0.895 < .001
4政党 失業率 失業率:マイナス1% -0.020 0.044 0.981 0.900 1.069 .656
5政党 政策位置 右派・保守的 -0.271 0.054 0.763 0.686 0.848 < .001
5政党 政策位置 左派・革新的 -0.419 0.056 0.657 0.589 0.734 < .001
5政党 与党/野党 与党 0.306 0.052 1.358 1.226 1.504 < .001
5政党 GDP成長率 GDP:プラス1% 0.389 0.046 1.475 1.348 1.615 < .001
5政党 GDP成長率 GDP:マイナス1% -0.228 0.048 0.796 0.725 0.874 < .001
5政党 日経平均 日経平均:プラス1000円 0.231 0.044 1.260 1.157 1.373 < .001
5政党 日経平均 日経平均:マイナス1000円 -0.323 0.046 0.724 0.662 0.792 < .001
5政党 議席数 議席数:10~49 0.275 0.052 1.317 1.190 1.457 < .001
5政党 議席数 議席数:50~99 0.544 0.060 1.722 1.530 1.938 < .001
5政党 議席数 議席数:100~199 0.643 0.068 1.902 1.665 2.172 < .001
5政党 議席数 議席数:200以上 0.651 0.070 1.917 1.671 2.199 < .001
5政党 CPI CPI:プラス1ポイント 0.054 0.044 1.055 0.969 1.149 .216
5政党 CPI CPI:マイナス1ポイント -0.083 0.045 0.920 0.843 1.005 .065
5政党 失業率 失業率:プラス1% -0.190 0.047 0.827 0.754 0.907 < .001
5政党 失業率 失業率:マイナス1% -0.005 0.045 0.995 0.911 1.087 .912

F. 実験2(2026年)の補足分析

本文では実験2のAMCEの方向性を記述し、詳細を補遺に回しているため、共変量調整済みAMCEを補図F1として最初に示す。

補図F1:共変量調整済みAMCE

補図F1データ <- study2_env$amce_plot_df_cov_facet
補図F1 <- study2_env$p_amce_cov_facet
補図F1

表F1 <- readr::read_csv(study_csv("study2", "table_amce_covariate_adjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表F1), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2政党条件 政策位置 右派・保守的 -1.96 1.61 -5.11 1.19 .223 711
2政党条件 政策位置 左派・革新的 -9.43 1.58 -12.53 -6.34 < .001 711
2政党条件 与党/野党 与党 3.43 1.31 0.87 5.99 .009 711
2政党条件 GDP成長率 GDP:プラス1% 8.29 1.56 5.23 11.35 < .001 711
2政党条件 GDP成長率 GDP:マイナス1% -5.54 1.52 -8.52 -2.56 < .001 711
2政党条件 日経平均 日経平均:プラス1000円 4.28 1.49 1.35 7.20 .004 711
2政党条件 日経平均 日経平均:マイナス1000円 -7.03 1.52 -10.01 -4.06 < .001 711
2政党条件 議席数 議席数:10~49 1.05 1.85 -2.58 4.67 .572 711
2政党条件 議席数 議席数:50~99 5.40 1.80 1.87 8.93 .003 711
2政党条件 議席数 議席数:100~199 8.38 2.00 4.46 12.30 < .001 711
2政党条件 議席数 議席数:200以上 8.34 1.99 4.43 12.24 < .001 711
2政党条件 CPI CPI:プラス1ポイント 1.84 1.43 -0.97 4.64 .200 711
2政党条件 CPI CPI:マイナス1ポイント 1.64 1.41 -1.13 4.40 .246 711
2政党条件 失業率 失業率:プラス1% -4.71 1.52 -7.69 -1.73 .002 711
2政党条件 失業率 失業率:マイナス1% -3.02 1.50 -5.96 -0.08 .045 711
3政党条件 政策位置 右派・保守的 -0.29 1.18 -2.59 2.02 .807 1062
3政党条件 政策位置 左派・革新的 -9.14 1.04 -11.19 -7.10 < .001 1062
3政党条件 与党/野党 与党 1.80 0.91 0.02 3.57 .048 1062
3政党条件 GDP成長率 GDP:プラス1% 5.85 0.97 3.95 7.75 < .001 1062
3政党条件 GDP成長率 GDP:マイナス1% -6.32 0.88 -8.05 -4.58 < .001 1062
3政党条件 日経平均 日経平均:プラス1000円 5.06 0.96 3.18 6.94 < .001 1062
3政党条件 日経平均 日経平均:マイナス1000円 -4.63 0.94 -6.46 -2.79 < .001 1062
3政党条件 議席数 議席数:10~49 3.52 1.17 1.23 5.81 .003 1062
3政党条件 議席数 議席数:50~99 7.32 1.19 4.99 9.65 < .001 1062
3政党条件 議席数 議席数:100~199 10.83 1.21 8.46 13.20 < .001 1062
3政党条件 議席数 議席数:200以上 10.08 1.25 7.63 12.52 < .001 1062
3政党条件 CPI CPI:プラス1ポイント 1.32 0.92 -0.47 3.12 .149 1062
3政党条件 CPI CPI:マイナス1ポイント -2.66 0.94 -4.51 -0.81 .005 1062
3政党条件 失業率 失業率:プラス1% -4.23 0.95 -6.09 -2.37 < .001 1062
3政党条件 失業率 失業率:マイナス1% -1.38 0.96 -3.26 0.50 .150 1062
4政党条件 政策位置 右派・保守的 1.11 0.98 -0.82 3.03 .260 1097
4政党条件 政策位置 左派・革新的 -8.64 0.86 -10.32 -6.96 < .001 1097
4政党条件 与党/野党 与党 1.85 0.72 0.43 3.27 .011 1097
4政党条件 GDP成長率 GDP:プラス1% 6.40 0.76 4.92 7.89 < .001 1097
4政党条件 GDP成長率 GDP:マイナス1% -4.84 0.69 -6.19 -3.50 < .001 1097
4政党条件 日経平均 日経平均:プラス1000円 2.72 0.77 1.20 4.23 < .001 1097
4政党条件 日経平均 日経平均:マイナス1000円 -5.12 0.71 -6.52 -3.73 < .001 1097
4政党条件 議席数 議席数:10~49 5.18 0.87 3.47 6.89 < .001 1097
4政党条件 議席数 議席数:50~99 8.18 0.94 6.34 10.02 < .001 1097
4政党条件 議席数 議席数:100~199 11.17 0.97 9.28 13.07 < .001 1097
4政党条件 議席数 議席数:200以上 11.28 1.02 9.28 13.29 < .001 1097
4政党条件 CPI CPI:プラス1ポイント 1.67 0.74 0.21 3.12 .025 1097
4政党条件 CPI CPI:マイナス1ポイント -0.57 0.73 -2.00 0.86 .433 1097
4政党条件 失業率 失業率:プラス1% -4.23 0.75 -5.70 -2.76 < .001 1097
4政党条件 失業率 失業率:マイナス1% -1.18 0.79 -2.73 0.37 .136 1097
5政党条件 政策位置 右派・保守的 1.01 0.78 -0.52 2.55 .195 1322
5政党条件 政策位置 左派・革新的 -6.08 0.68 -7.42 -4.75 < .001 1322
5政党条件 与党/野党 与党 2.76 0.55 1.68 3.83 < .001 1322
5政党条件 GDP成長率 GDP:プラス1% 5.07 0.59 3.91 6.23 < .001 1322
5政党条件 GDP成長率 GDP:マイナス1% -2.96 0.52 -3.98 -1.94 < .001 1322
5政党条件 日経平均 日経平均:プラス1000円 4.09 0.58 2.97 5.22 < .001 1322
5政党条件 日経平均 日経平均:マイナス1000円 -3.13 0.55 -4.20 -2.07 < .001 1322
5政党条件 議席数 議席数:10~49 2.26 0.63 1.02 3.50 < .001 1322
5政党条件 議席数 議席数:50~99 6.91 0.70 5.54 8.28 < .001 1322
5政党条件 議席数 議席数:100~199 9.65 0.75 8.18 11.12 < .001 1322
5政党条件 議席数 議席数:200以上 10.56 0.77 9.05 12.08 < .001 1322
5政党条件 CPI CPI:プラス1ポイント 0.28 0.54 -0.78 1.35 .602 1322
5政党条件 CPI CPI:マイナス1ポイント -0.43 0.55 -1.50 0.65 .436 1322
5政党条件 失業率 失業率:プラス1% -2.36 0.55 -3.43 -1.28 < .001 1322
5政党条件 失業率 失業率:マイナス1% -0.19 0.59 -1.34 0.97 .753 1322

補図F2:共変量を含めないAMCE

補図F2データ <- study2_env$amce_plot_df_nocov_facet
補図F2 <- study2_env$p_amce_facet_nocov
補図F2

表F2 <- readr::read_csv(study_csv("study2", "table_amce_unadjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表F2), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2政党条件 政策位置 右派・保守的 -1.94 1.60 -5.08 1.19 .225 711
2政党条件 政策位置 左派・革新的 -9.40 1.57 -12.48 -6.31 < .001 711
2政党条件 与党/野党 与党 3.43 1.30 0.88 5.98 .009 711
2政党条件 GDP成長率 GDP:プラス1% 8.26 1.56 5.21 11.31 < .001 711
2政党条件 GDP成長率 GDP:マイナス1% -5.53 1.51 -8.49 -2.56 < .001 711
2政党条件 日経平均 日経平均:プラス1000円 4.27 1.49 1.36 7.18 .004 711
2政党条件 日経平均 日経平均:マイナス1000円 -7.01 1.51 -9.97 -4.05 < .001 711
2政党条件 議席数 議席数:10~49 1.03 1.84 -2.59 4.64 .578 711
2政党条件 議席数 議席数:50~99 5.37 1.79 1.86 8.89 .003 711
2政党条件 議席数 議席数:100~199 8.35 1.99 4.45 12.25 < .001 711
2政党条件 議席数 議席数:200以上 8.33 1.98 4.44 12.21 < .001 711
2政党条件 CPI CPI:プラス1ポイント 1.85 1.43 -0.95 4.64 .195 711
2政党条件 CPI CPI:マイナス1ポイント 1.62 1.40 -1.14 4.37 .250 711
2政党条件 失業率 失業率:プラス1% -4.72 1.51 -7.68 -1.75 .002 711
2政党条件 失業率 失業率:マイナス1% -3.02 1.49 -5.95 -0.10 .043 711
3政党条件 政策位置 右派・保守的 -0.28 1.17 -2.58 2.02 .810 1062
3政党条件 政策位置 左派・革新的 -9.12 1.04 -11.16 -7.08 < .001 1062
3政党条件 与党/野党 与党 1.79 0.91 0.01 3.56 .049 1062
3政党条件 GDP成長率 GDP:プラス1% 5.85 0.97 3.95 7.74 < .001 1062
3政党条件 GDP成長率 GDP:マイナス1% -6.31 0.88 -8.03 -4.58 < .001 1062
3政党条件 日経平均 日経平均:プラス1000円 5.05 0.96 3.18 6.93 < .001 1062
3政党条件 日経平均 日経平均:マイナス1000円 -4.62 0.93 -6.46 -2.79 < .001 1062
3政党条件 議席数 議席数:10~49 3.52 1.17 1.23 5.81 .003 1062
3政党条件 議席数 議席数:50~99 7.31 1.19 4.99 9.63 < .001 1062
3政党条件 議席数 議席数:100~199 10.81 1.21 8.45 13.18 < .001 1062
3政党条件 議席数 議席数:200以上 10.06 1.24 7.62 12.50 < .001 1062
3政党条件 CPI CPI:プラス1ポイント 1.33 0.92 -0.47 3.13 .148 1062
3政党条件 CPI CPI:マイナス1ポイント -2.66 0.94 -4.51 -0.81 .005 1062
3政党条件 失業率 失業率:プラス1% -4.23 0.95 -6.08 -2.37 < .001 1062
3政党条件 失業率 失業率:マイナス1% -1.39 0.96 -3.26 0.49 .147 1062
4政党条件 政策位置 右派・保守的 1.11 0.98 -0.82 3.03 .260 1097
4政党条件 政策位置 左派・革新的 -8.63 0.86 -10.31 -6.96 < .001 1097
4政党条件 与党/野党 与党 1.85 0.72 0.43 3.27 .011 1097
4政党条件 GDP成長率 GDP:プラス1% 6.40 0.76 4.91 7.88 < .001 1097
4政党条件 GDP成長率 GDP:マイナス1% -4.84 0.69 -6.18 -3.50 < .001 1097
4政党条件 日経平均 日経平均:プラス1000円 2.72 0.77 1.20 4.23 < .001 1097
4政党条件 日経平均 日経平均:マイナス1000円 -5.12 0.71 -6.51 -3.73 < .001 1097
4政党条件 議席数 議席数:10~49 5.18 0.87 3.47 6.88 < .001 1097
4政党条件 議席数 議席数:50~99 8.17 0.94 6.33 10.01 < .001 1097
4政党条件 議席数 議席数:100~199 11.17 0.96 9.28 13.06 < .001 1097
4政党条件 議席数 議席数:200以上 11.28 1.02 9.28 13.28 < .001 1097
4政党条件 CPI CPI:プラス1ポイント 1.67 0.74 0.22 3.12 .024 1097
4政党条件 CPI CPI:マイナス1ポイント -0.57 0.73 -1.99 0.86 .435 1097
4政党条件 失業率 失業率:プラス1% -4.22 0.75 -5.69 -2.75 < .001 1097
4政党条件 失業率 失業率:マイナス1% -1.18 0.79 -2.73 0.37 .137 1097
5政党条件 政策位置 右派・保守的 1.02 0.78 -0.51 2.55 .194 1322
5政党条件 政策位置 左派・革新的 -6.08 0.68 -7.41 -4.75 < .001 1322
5政党条件 与党/野党 与党 2.75 0.55 1.67 3.82 < .001 1322
5政党条件 GDP成長率 GDP:プラス1% 5.07 0.59 3.91 6.23 < .001 1322
5政党条件 GDP成長率 GDP:マイナス1% -2.96 0.52 -3.97 -1.94 < .001 1322
5政党条件 日経平均 日経平均:プラス1000円 4.09 0.57 2.96 5.22 < .001 1322
5政党条件 日経平均 日経平均:マイナス1000円 -3.13 0.55 -4.20 -2.06 < .001 1322
5政党条件 議席数 議席数:10~49 2.26 0.63 1.02 3.50 < .001 1322
5政党条件 議席数 議席数:50~99 6.91 0.70 5.54 8.27 < .001 1322
5政党条件 議席数 議席数:100~199 9.65 0.75 8.18 11.12 < .001 1322
5政党条件 議席数 議席数:200以上 10.56 0.77 9.05 12.07 < .001 1322
5政党条件 CPI CPI:プラス1ポイント 0.28 0.54 -0.78 1.35 .602 1322
5政党条件 CPI CPI:マイナス1ポイント -0.42 0.55 -1.50 0.65 .438 1322
5政党条件 失業率 失業率:プラス1% -2.36 0.55 -3.44 -1.28 < .001 1322
5政党条件 失業率 失業率:マイナス1% -0.19 0.59 -1.34 0.96 .749 1322

補図F3:2政党条件との差

補図F3データ <- study2_env$interaction_plot_df
補図F3 <- study2_env$p_interaction
補図F3

表F3 <- readr::read_csv(study_csv("study2", "table_amce_interaction.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, attribute = "属性")) %>%
  dplyr::mutate(dplyr::across(dplyr::any_of("属性"), 属性日本語))
knitr::kable(表日本語(表F3), format = "html", row.names = FALSE)
比較条件 属性 水準 2選択肢条件との差(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値
3政党 政策位置 右派・保守的 1.66 1.98 -2.22 5.55 0.402
4政党 政策位置 右派・保守的 3.05 1.88 -0.63 6.73 0.104
5政党 政策位置 右派・保守的 2.96 1.78 -0.53 6.45 0.096
3政党 政策位置 左派・革新的 0.28 1.88 -3.42 3.97 0.882
4政党 政策位置 左派・革新的 0.77 1.79 -2.74 4.27 0.668
5政党 政策位置 左派・革新的 3.32 1.71 -0.04 6.68 0.053
3政党 与党/野党 与党 -1.64 1.58 -4.74 1.46 0.300
4政党 与党/野党 与党 -1.58 1.49 -4.49 1.33 0.288
5政党 与党/野党 与党 -0.68 1.41 -3.44 2.08 0.630
3政党 GDP成長率 GDP:プラス1% -2.42 1.83 -6.00 1.17 0.187
4政党 GDP成長率 GDP:プラス1% -1.87 1.73 -5.25 1.52 0.280
5政党 GDP成長率 GDP:プラス1% -3.20 1.66 -6.45 0.06 0.055
3政党 GDP成長率 GDP:マイナス1% -0.78 1.75 -4.21 2.65 0.656
4政党 GDP成長率 GDP:マイナス1% 0.69 1.66 -2.56 3.93 0.679
5政党 GDP成長率 GDP:マイナス1% 2.57 1.60 -0.56 5.70 0.108
3政党 日経平均 日経平均:プラス1000円 0.78 1.77 -2.68 4.24 0.658
4政党 日経平均 日経平均:プラス1000円 -1.56 1.67 -4.83 1.72 0.353
5政党 日経平均 日経平均:プラス1000円 -0.18 1.59 -3.30 2.94 0.909
3政党 日経平均 日経平均:マイナス1000円 2.39 1.78 -1.09 5.87 0.179
4政党 日経平均 日経平均:マイナス1000円 1.89 1.67 -1.38 5.16 0.257
5政党 日経平均 日経平均:マイナス1000円 3.88 1.60 0.73 7.02 0.016
3政党 議席数 議席数:10~49 2.49 2.18 -1.79 6.76 0.254
4政党 議席数 議席数:10~49 4.15 2.04 0.16 8.14 0.042
5政党 議席数 議席数:10~49 1.23 1.95 -2.58 5.05 0.527
3政党 議席数 議席数:50~99 1.94 2.15 -2.27 6.15 0.367
4政党 議席数 議席数:50~99 2.80 2.02 -1.17 6.76 0.167
5政党 議席数 議席数:50~99 1.53 1.92 -2.24 5.30 0.425
3政党 議席数 議席数:100~199 2.46 2.32 -2.09 7.02 0.289
4政党 議席数 議席数:100~199 2.82 2.21 -1.51 7.15 0.202
5政党 議席数 議席数:100~199 1.30 2.12 -2.87 5.46 0.542
3政党 議席数 議席数:200以上 1.74 2.34 -2.85 6.32 0.458
4政党 議席数 議席数:200以上 2.95 2.23 -1.42 7.32 0.185
5政党 議席数 議席数:200以上 2.23 2.13 -1.93 6.40 0.293
3政党 CPI CPI:プラス1ポイント -0.52 1.69 -3.84 2.80 0.759
4政党 CPI CPI:プラス1ポイント -0.18 1.61 -3.32 2.97 0.912
5政党 CPI CPI:プラス1ポイント -1.56 1.52 -4.55 1.42 0.305
3政党 CPI CPI:マイナス1ポイント -4.28 1.69 -7.59 -0.97 0.011
4政党 CPI CPI:マイナス1ポイント -2.18 1.58 -5.28 0.91 0.167
5政党 CPI CPI:マイナス1ポイント -2.04 1.51 -4.99 0.91 0.175
3政党 失業率 失業率:プラス1% 0.49 1.78 -3.00 3.99 0.782
4政党 失業率 失業率:プラス1% 0.50 1.69 -2.81 3.80 0.769
5政党 失業率 失業率:プラス1% 2.36 1.61 -0.79 5.51 0.142
3政党 失業率 失業率:マイナス1% 1.64 1.77 -1.84 5.11 0.355
4政党 失業率 失業率:マイナス1% 1.85 1.69 -1.46 5.16 0.274
5政党 失業率 失業率:マイナス1% 2.84 1.60 -0.31 5.98 0.077

補図F4:条件付きロジット

補図F4 <- study2_env$p_clogit_or
補図F4

表F4 <- readr::read_csv(study_csv("study2", "table_conditional_logit.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", label = "水準")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study2"), 属性 = 属性日本語(属性)) %>%
  dplyr::select(-dplyr::any_of(c("term", "variable", "policy_position", "government_status")))
knitr::kable(表日本語(表F4), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) log係数 標準誤差 オッズ比 95% CI下限(OR) 95% CI上限(OR) p値
2政党 政策位置 右派・保守的 -0.086 0.072 0.918 0.797 1.057 .234
2政党 政策位置 左派・革新的 -0.408 0.069 0.665 0.581 0.762 < .001
2政党 与党/野党 与党 0.137 0.054 1.147 1.031 1.276 .012
2政党 GDP成長率 GDP:プラス1% 0.346 0.065 1.413 1.245 1.603 < .001
2政党 GDP成長率 GDP:マイナス1% -0.224 0.063 0.799 0.706 0.905 < .001
2政党 日経平均 日経平均:プラス1000円 0.187 0.063 1.205 1.066 1.363 .003
2政党 日経平均 日経平均:マイナス1000円 -0.294 0.064 0.745 0.658 0.844 < .001
2政党 議席数 議席数:10~49 0.054 0.076 1.056 0.910 1.225 .474
2政党 議席数 議席数:50~99 0.254 0.079 1.290 1.105 1.505 .001
2政党 議席数 議席数:100~199 0.349 0.084 1.418 1.202 1.672 < .001
2政党 議席数 議席数:200以上 0.351 0.087 1.420 1.199 1.683 < .001
2政党 CPI CPI:プラス1ポイント 0.099 0.062 1.104 0.977 1.247 .112
2政党 CPI CPI:マイナス1ポイント 0.087 0.061 1.091 0.968 1.230 .153
2政党 失業率 失業率:プラス1% -0.190 0.064 0.827 0.729 0.938 .003
2政党 失業率 失業率:マイナス1% -0.131 0.064 0.877 0.774 0.993 .039
3政党 政策位置 右派・保守的 -0.014 0.053 0.986 0.889 1.093 .791
3政党 政策位置 左派・革新的 -0.444 0.051 0.641 0.580 0.709 < .001
3政党 与党/野党 与党 0.089 0.042 1.093 1.006 1.187 .036
3政党 GDP成長率 GDP:プラス1% 0.263 0.043 1.301 1.196 1.415 < .001
3政党 GDP成長率 GDP:マイナス1% -0.309 0.043 0.734 0.675 0.798 < .001
3政党 日経平均 日経平均:プラス1000円 0.228 0.044 1.256 1.153 1.369 < .001
3政党 日経平均 日経平均:マイナス1000円 -0.232 0.046 0.793 0.724 0.869 < .001
3政党 議席数 議席数:10~49 0.182 0.060 1.200 1.066 1.350 .003
3政党 議席数 議席数:50~99 0.377 0.060 1.457 1.295 1.640 < .001
3政党 議席数 議席数:100~199 0.536 0.060 1.710 1.519 1.924 < .001
3政党 議席数 議席数:200以上 0.495 0.062 1.640 1.454 1.850 < .001
3政党 CPI CPI:プラス1ポイント 0.066 0.043 1.068 0.983 1.161 .120
3政党 CPI CPI:マイナス1ポイント -0.117 0.045 0.890 0.815 0.971 .009
3政党 失業率 失業率:プラス1% -0.200 0.044 0.819 0.751 0.893 < .001
3政党 失業率 失業率:マイナス1% -0.063 0.044 0.939 0.862 1.024 .156
4政党 政策位置 右派・保守的 0.053 0.050 1.055 0.957 1.163 .285
4政党 政策位置 左派・革新的 -0.519 0.052 0.595 0.538 0.659 < .001
4政党 与党/野党 与党 0.099 0.040 1.104 1.020 1.195 .014
4政党 GDP成長率 GDP:プラス1% 0.340 0.040 1.405 1.300 1.518 < .001
4政党 GDP成長率 GDP:マイナス1% -0.294 0.042 0.745 0.687 0.809 < .001
4政党 日経平均 日経平均:プラス1000円 0.142 0.040 1.152 1.065 1.247 < .001
4政党 日経平均 日経平均:マイナス1000円 -0.300 0.042 0.741 0.683 0.804 < .001
4政党 議席数 議席数:10~49 0.331 0.056 1.392 1.247 1.553 < .001
4政党 議席数 議席数:50~99 0.497 0.058 1.645 1.467 1.844 < .001
4政党 議席数 議席数:100~199 0.656 0.059 1.927 1.716 2.163 < .001
4政党 議席数 議席数:200以上 0.656 0.062 1.928 1.709 2.175 < .001
4政党 CPI CPI:プラス1ポイント 0.098 0.040 1.103 1.019 1.194 .015
4政党 CPI CPI:マイナス1ポイント -0.031 0.041 0.969 0.894 1.051 .447
4政党 失業率 失業率:プラス1% -0.232 0.042 0.793 0.730 0.862 < .001
4政党 失業率 失業率:マイナス1% -0.065 0.043 0.937 0.862 1.019 .127
5政党 政策位置 右派・保守的 0.064 0.047 1.066 0.973 1.168 .173
5政党 政策位置 左派・革新的 -0.418 0.047 0.658 0.600 0.722 < .001
5政党 与党/野党 与党 0.185 0.036 1.203 1.121 1.291 < .001
5政党 GDP成長率 GDP:プラス1% 0.311 0.036 1.365 1.272 1.464 < .001
5政党 GDP成長率 GDP:マイナス1% -0.209 0.037 0.812 0.755 0.873 < .001
5政党 日経平均 日経平均:プラス1000円 0.245 0.035 1.278 1.193 1.369 < .001
5政党 日経平均 日経平均:マイナス1000円 -0.221 0.038 0.802 0.745 0.864 < .001
5政党 議席数 議席数:10~49 0.182 0.050 1.200 1.087 1.324 < .001
5政党 議席数 議席数:50~99 0.493 0.050 1.638 1.484 1.808 < .001
5政党 議席数 議席数:100~199 0.665 0.053 1.945 1.752 2.159 < .001
5政党 議席数 議席数:200以上 0.716 0.054 2.047 1.843 2.274 < .001
5政党 CPI CPI:プラス1ポイント 0.023 0.035 1.023 0.955 1.096 .513
5政党 CPI CPI:マイナス1ポイント -0.027 0.036 0.973 0.907 1.044 .443
5政党 失業率 失業率:プラス1% -0.160 0.036 0.852 0.794 0.914 < .001
5政党 失業率 失業率:マイナス1% -0.016 0.037 0.985 0.916 1.058 .674

G. 実験3(2026年)の補足分析

補図G1:共変量を含めないAMCE

補図G1データ <- study3_env$amce_plot_nocov
補図G1 <- study3_env$p_amce_nocov
補図G1

表G1 <- readr::read_csv(study_csv("study3", "table_amce_unadjusted.csv"), show_col_types = FALSE) %>%
  dplyr::mutate(条件 = paste0(stringr::str_remove(条件, "条件$"), "条件"))
knitr::kable(表日本語(表G1), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) 推定値(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値 回答者数
2選択肢条件 政権与党の政党名 立憲民主党 -8.81 3.11 -14.91 -2.72 .005 716
2選択肢条件 政権与党の政党名 日本維新の会 -5.98 2.76 -11.39 -0.56 .031 716
2選択肢条件 政権与党の政党名 公明党 -23.50 2.89 -29.17 -17.83 < .001 716
2選択肢条件 政権与党の政党名 国民民主党 -1.24 2.79 -6.71 4.24 .659 716
2選択肢条件 政権与党の政党名 れいわ新選組 -28.29 3.03 -34.23 -22.36 < .001 716
2選択肢条件 政権与党の政党名 参政党 -14.93 2.76 -20.35 -9.52 < .001 716
2選択肢条件 政権与党の政党名 日本共産党 -33.63 2.89 -39.30 -27.95 < .001 716
2選択肢条件 政権与党の政党名 中道改革連合 -12.51 2.91 -18.22 -6.80 < .001 716
2選択肢条件 政権与党の政党名 チームみらい -5.10 2.81 -10.60 0.40 .070 716
2選択肢条件 GDP成長率 GDP:プラス1% 7.63 1.43 4.82 10.44 < .001 716
2選択肢条件 GDP成長率 GDP:マイナス1% -5.89 1.44 -8.71 -3.07 < .001 716
2選択肢条件 日経平均 日経平均:プラス1000円 2.84 1.41 0.07 5.61 .045 716
2選択肢条件 日経平均 日経平均:マイナス1000円 -5.26 1.43 -8.06 -2.46 < .001 716
2選択肢条件 CPI CPI:プラス1ポイント -0.48 1.42 -3.26 2.30 .733 716
2選択肢条件 CPI CPI:マイナス1ポイント -2.27 1.43 -5.07 0.52 .112 716
2選択肢条件 失業率 失業率:プラス1% -6.06 1.42 -8.85 -3.27 < .001 716
2選択肢条件 失業率 失業率:マイナス1% -1.49 1.42 -4.26 1.29 .295 716
3選択肢条件 政権与党の政党名 立憲民主党 -13.87 2.26 -18.29 -9.45 < .001 939
3選択肢条件 政権与党の政党名 日本維新の会 -9.01 2.05 -13.02 -5.00 < .001 939
3選択肢条件 政権与党の政党名 公明党 -25.30 2.00 -29.22 -21.38 < .001 939
3選択肢条件 政権与党の政党名 国民民主党 -2.58 2.15 -6.79 1.64 .231 939
3選択肢条件 政権与党の政党名 れいわ新選組 -26.00 2.18 -30.28 -21.73 < .001 939
3選択肢条件 政権与党の政党名 参政党 -12.43 2.15 -16.66 -8.21 < .001 939
3選択肢条件 政権与党の政党名 日本共産党 -28.06 2.15 -32.28 -23.84 < .001 939
3選択肢条件 政権与党の政党名 中道改革連合 -18.36 2.26 -22.78 -13.94 < .001 939
3選択肢条件 政権与党の政党名 チームみらい -8.30 2.16 -12.53 -4.07 < .001 939
3選択肢条件 GDP成長率 GDP:プラス1% 7.09 1.00 5.14 9.05 < .001 939
3選択肢条件 GDP成長率 GDP:マイナス1% -4.80 0.97 -6.70 -2.89 < .001 939
3選択肢条件 日経平均 日経平均:プラス1000円 3.37 1.02 1.37 5.38 .001 939
3選択肢条件 日経平均 日経平均:マイナス1000円 -5.28 0.94 -7.13 -3.43 < .001 939
3選択肢条件 CPI CPI:プラス1ポイント -0.44 0.96 -2.32 1.44 .645 939
3選択肢条件 CPI CPI:マイナス1ポイント -1.37 0.94 -3.21 0.46 .143 939
3選択肢条件 失業率 失業率:プラス1% -4.46 0.96 -6.34 -2.58 < .001 939
3選択肢条件 失業率 失業率:マイナス1% -1.96 0.97 -3.86 -0.05 .044 939
4選択肢条件 政権与党の政党名 立憲民主党 -16.33 1.88 -20.01 -12.64 < .001 1063
4選択肢条件 政権与党の政党名 日本維新の会 -9.34 1.73 -12.73 -5.95 < .001 1063
4選択肢条件 政権与党の政党名 公明党 -24.43 1.67 -27.71 -21.16 < .001 1063
4選択肢条件 政権与党の政党名 国民民主党 -4.96 1.80 -8.49 -1.43 .006 1063
4選択肢条件 政権与党の政党名 れいわ新選組 -25.30 1.75 -28.74 -21.86 < .001 1063
4選択肢条件 政権与党の政党名 参政党 -12.36 1.81 -15.91 -8.81 < .001 1063
4選択肢条件 政権与党の政党名 日本共産党 -25.65 1.80 -29.17 -22.13 < .001 1063
4選択肢条件 政権与党の政党名 中道改革連合 -17.92 1.92 -21.69 -14.15 < .001 1063
4選択肢条件 政権与党の政党名 チームみらい -11.29 1.89 -14.99 -7.58 < .001 1063
4選択肢条件 GDP成長率 GDP:プラス1% 5.03 0.76 3.54 6.52 < .001 1063
4選択肢条件 GDP成長率 GDP:マイナス1% -3.49 0.72 -4.91 -2.08 < .001 1063
4選択肢条件 日経平均 日経平均:プラス1000円 3.87 0.80 2.31 5.43 < .001 1063
4選択肢条件 日経平均 日経平均:マイナス1000円 -3.32 0.72 -4.74 -1.90 < .001 1063
4選択肢条件 CPI CPI:プラス1ポイント 0.54 0.73 -0.89 1.98 .457 1063
4選択肢条件 CPI CPI:マイナス1ポイント -1.25 0.73 -2.69 0.19 .088 1063
4選択肢条件 失業率 失業率:プラス1% -3.72 0.71 -5.11 -2.33 < .001 1063
4選択肢条件 失業率 失業率:マイナス1% -2.01 0.73 -3.44 -0.58 .006 1063
5選択肢条件 政権与党の政党名 立憲民主党 -12.98 1.59 -16.10 -9.86 < .001 1314
5選択肢条件 政権与党の政党名 日本維新の会 -8.62 1.42 -11.40 -5.84 < .001 1314
5選択肢条件 政権与党の政党名 公明党 -21.75 1.38 -24.46 -19.03 < .001 1314
5選択肢条件 政権与党の政党名 国民民主党 -5.06 1.49 -7.98 -2.14 < .001 1314
5選択肢条件 政権与党の政党名 れいわ新選組 -21.60 1.41 -24.37 -18.83 < .001 1314
5選択肢条件 政権与党の政党名 参政党 -13.07 1.49 -16.00 -10.15 < .001 1314
5選択肢条件 政権与党の政党名 日本共産党 -21.87 1.42 -24.65 -19.09 < .001 1314
5選択肢条件 政権与党の政党名 中道改革連合 -16.65 1.50 -19.60 -13.70 < .001 1314
5選択肢条件 政権与党の政党名 チームみらい -12.21 1.51 -15.16 -9.26 < .001 1314
5選択肢条件 GDP成長率 GDP:プラス1% 5.48 0.59 4.32 6.64 < .001 1314
5選択肢条件 GDP成長率 GDP:マイナス1% -2.10 0.52 -3.13 -1.08 < .001 1314
5選択肢条件 日経平均 日経平均:プラス1000円 3.78 0.55 2.70 4.86 < .001 1314
5選択肢条件 日経平均 日経平均:マイナス1000円 -2.15 0.53 -3.19 -1.12 < .001 1314
5選択肢条件 CPI CPI:プラス1ポイント 0.42 0.53 -0.62 1.47 .430 1314
5選択肢条件 CPI CPI:マイナス1ポイント -0.10 0.55 -1.18 0.99 .863 1314
5選択肢条件 失業率 失業率:プラス1% -2.85 0.55 -3.93 -1.76 < .001 1314
5選択肢条件 失業率 失業率:マイナス1% -0.89 0.55 -1.98 0.19 .107 1314

補図G2:2選択肢条件との差

補図G2 <- study3_env$p_interaction
補図G2

表G2 <- readr::read_csv(study_csv("study3", "table_amce_interaction.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, attribute = "属性")) %>%
  dplyr::mutate(dplyr::across(dplyr::any_of("属性"), 属性日本語))
knitr::kable(表日本語(表G2), format = "html", row.names = FALSE)
比較条件 属性 水準 2選択肢条件との差(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値
3選択肢 政権与党の政党名 立憲民主党 -5.05 3.84 -12.57 2.47 .188
4選択肢 政権与党の政党名 立憲民主党 -7.51 3.63 -14.62 -0.40 .038
5選択肢 政権与党の政党名 立憲民主党 -4.16 3.49 -11.00 2.67 .233
3選択肢 政権与党の政党名 日本維新の会 -3.03 3.43 -9.77 3.70 .377
4選択肢 政権与党の政党名 日本維新の会 -3.36 3.26 -9.74 3.02 .302
5選択肢 政権与党の政党名 日本維新の会 -2.65 3.10 -8.72 3.43 .394
3選択肢 政権与党の政党名 公明党 -1.80 3.51 -8.69 5.08 .608
4選択肢 政権与党の政党名 公明党 -0.93 3.34 -7.48 5.61 .780
5選択肢 政権与党の政党名 公明党 1.75 3.20 -4.53 8.03 .584
3選択肢 政権与党の政党名 国民民主党 -1.34 3.52 -8.24 5.56 .703
4選択肢 政権与党の政党名 国民民主党 -3.72 3.32 -10.24 2.79 .262
5選択肢 政権与党の政党名 国民民主党 -3.83 3.16 -10.03 2.38 .227
3選択肢 政権与党の政党名 れいわ新選組 2.29 3.73 -5.02 9.60 .539
4選択肢 政権与党の政党名 れいわ新選組 2.99 3.50 -3.86 9.84 .392
5選択肢 政権与党の政党名 れいわ新選組 6.69 3.34 0.15 13.24 .045
3選択肢 政権与党の政党名 参政党 2.50 3.50 -4.36 9.36 .475
4選択肢 政権与党の政党名 参政党 2.57 3.30 -3.89 9.04 .436
5選択肢 政権与党の政党名 参政党 1.86 3.14 -4.29 8.01 .553
3選択肢 政権与党の政党名 日本共産党 5.57 3.60 -1.49 12.63 .122
4選択肢 政権与党の政党名 日本共産党 7.98 3.40 1.31 14.65 .019
5選択肢 政権与党の政党名 日本共産党 11.76 3.22 5.44 18.07 < .001
3選択肢 政権与党の政党名 中道改革連合 -5.85 3.68 -13.07 1.36 .112
4選択肢 政権与党の政党名 中道改革連合 -5.41 3.49 -12.25 1.42 .121
5選択肢 政権与党の政党名 中道改革連合 -4.15 3.28 -10.56 2.27 .206
3選択肢 政権与党の政党名 チームみらい -3.20 3.54 -10.13 3.73 .365
4選択肢 政権与党の政党名 チームみらい -6.19 3.38 -12.81 0.44 .067
5選択肢 政権与党の政党名 チームみらい -7.11 3.18 -13.35 -0.87 .026
3選択肢 GDP成長率 GDP:プラス1% -0.54 1.75 -3.96 2.88 .758
4選択肢 GDP成長率 GDP:プラス1% -2.60 1.62 -5.78 0.58 .109
5選択肢 GDP成長率 GDP:プラス1% -2.15 1.55 -5.19 0.89 .165
3選択肢 GDP成長率 GDP:マイナス1% 1.09 1.73 -2.31 4.49 .529
4選択肢 GDP成長率 GDP:マイナス1% 2.39 1.61 -0.76 5.54 .136
5選択肢 GDP成長率 GDP:マイナス1% 3.78 1.53 0.79 6.78 .013
3選択肢 日経平均 日経平均:プラス1000円 0.53 1.74 -2.88 3.95 .759
4選択肢 日経平均 日経平均:プラス1000円 1.03 1.62 -2.14 4.21 .525
5選択肢 日経平均 日経平均:プラス1000円 0.94 1.52 -2.03 3.91 .535
3選択肢 日経平均 日経平均:マイナス1000円 -0.02 1.71 -3.37 3.33 .991
4選択肢 日経平均 日経平均:マイナス1000円 1.94 1.60 -1.20 5.07 .226
5選択肢 日経平均 日経平均:マイナス1000円 3.11 1.52 0.12 6.09 .041
3選択肢 CPI CPI:プラス1ポイント 0.04 1.71 -3.31 3.40 .980
4選択肢 CPI CPI:プラス1ポイント 1.03 1.59 -2.10 4.15 .519
5選択肢 CPI CPI:プラス1ポイント 0.91 1.51 -2.06 3.87 .550
3選択肢 CPI CPI:マイナス1ポイント 0.90 1.71 -2.44 4.24 .598
4選択肢 CPI CPI:マイナス1ポイント 1.02 1.60 -2.12 4.16 .525
5選択肢 CPI CPI:マイナス1ポイント 2.18 1.53 -0.82 5.18 .154
3選択肢 失業率 失業率:プラス1% 1.59 1.72 -1.77 4.96 .353
4選択肢 失業率 失業率:プラス1% 2.34 1.59 -0.78 5.45 .142
5選択肢 失業率 失業率:プラス1% 3.21 1.53 0.22 6.21 .035
3選択肢 失業率 失業率:マイナス1% -0.47 1.72 -3.84 2.89 .784
4選択肢 失業率 失業率:マイナス1% -0.53 1.59 -3.65 2.59 .740
5選択肢 失業率 失業率:マイナス1% 0.59 1.52 -2.39 3.57 .697

補図G3:AMCEの線形トレンド

補図G3 <- study3_env$p_linear_trend
補図G3

表G3 <- readr::read_csv(study_csv("study3", "table_amce_linear_trend.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, attribute = "属性", label = "水準")) %>%
  dplyr::mutate(dplyr::across(dplyr::any_of("属性"), 属性日本語)) %>%
  dplyr::select(-dplyr::any_of(c("term", "variable")))
knitr::kable(表日本語(表G3), format = "html", row.names = FALSE)
属性 水準 選択肢が1つ増えるときの変化(pp) 標準誤差(pp) 95% CI下限(pp) 95% CI上限(pp) p値
政権与党の政党名 立憲民主党 -0.61 1.00 -2.57 1.36 .545
政権与党の政党名 日本維新の会 -0.47 0.89 -2.22 1.28 .599
政権与党の政党名 公明党 1.10 0.90 -0.66 2.85 .221
政権与党の政党名 国民民主党 -1.22 0.93 -3.04 0.60 .189
政権与党の政党名 れいわ新選組 2.28 0.94 0.45 4.12 .015
政権与党の政党名 参政党 0.18 0.92 -1.62 1.99 .844
政権与党の政党名 日本共産党 3.61 0.92 1.81 5.40 < .001
政権与党の政党名 中道改革連合 -0.44 0.96 -2.31 1.43 .644
政権与党の政党名 チームみらい -2.19 0.93 -4.01 -0.36 .019
GDP成長率 GDP:プラス1% -0.74 0.42 -1.57 0.09 .079
GDP成長率 GDP:マイナス1% 1.29 0.40 0.50 2.08 .001
日経平均 日経平均:プラス1000円 0.29 0.41 -0.52 1.10 .483
日経平均 日経平均:マイナス1000円 1.24 0.40 0.45 2.03 .002
CPI CPI:プラス1ポイント 0.36 0.40 -0.43 1.15 .372
CPI CPI:マイナス1ポイント 0.70 0.40 -0.09 1.49 .083
失業率 失業率:プラス1% 0.97 0.41 0.17 1.77 .018
失業率 失業率:マイナス1% 0.39 0.41 -0.42 1.19 .346

補図G4:条件付きロジット

補図G4 <- study3_env$p_clogit_or
補図G4

表G4 <- readr::read_csv(study_csv("study3", "table_conditional_logit.csv"), show_col_types = FALSE) %>%
  dplyr::rename_with(~ dplyr::recode(.x, party_n = "条件", attribute = "属性", label = "水準")) %>%
  dplyr::mutate(条件 = 条件日本語(条件, "study3"), 属性 = 属性日本語(属性)) %>%
  dplyr::select(-dplyr::any_of(c("term", "variable")))
knitr::kable(表日本語(表G4), format = "html", row.names = FALSE)
条件 属性 水準(基準水準との差) log係数 標準誤差 オッズ比 95% CI下限(OR) 95% CI上限(OR) p値
2選択肢 政権与党の政党名 立憲民主党 -0.328 0.123 0.721 0.567 0.916 .008
2選択肢 政権与党の政党名 日本維新の会 -0.248 0.111 0.781 0.628 0.970 .026
2選択肢 政権与党の政党名 公明党 -0.952 0.118 0.386 0.306 0.486 < .001
2選択肢 政権与党の政党名 国民民主党 -0.056 0.114 0.946 0.756 1.183 .625
2選択肢 政権与党の政党名 れいわ新選組 -1.155 0.129 0.315 0.245 0.406 < .001
2選択肢 政権与党の政党名 参政党 -0.598 0.110 0.550 0.443 0.682 < .001
2選択肢 政権与党の政党名 日本共産党 -1.364 0.129 0.256 0.199 0.329 < .001
2選択肢 政権与党の政党名 中道改革連合 -0.524 0.118 0.592 0.470 0.746 < .001
2選択肢 政権与党の政党名 チームみらい -0.206 0.110 0.814 0.655 1.011 .062
2選択肢 GDP成長率 GDP:プラス1% 0.363 0.066 1.438 1.264 1.635 < .001
2選択肢 GDP成長率 GDP:マイナス1% -0.266 0.064 0.766 0.676 0.869 < .001
2選択肢 日経平均 日経平均:プラス1000円 0.133 0.063 1.143 1.009 1.294 .035
2選択肢 日経平均 日経平均:マイナス1000円 -0.248 0.064 0.781 0.688 0.886 < .001
2選択肢 CPI CPI:プラス1ポイント -0.021 0.063 0.980 0.865 1.109 .746
2選択肢 CPI CPI:マイナス1ポイント -0.120 0.063 0.887 0.784 1.003 .055
2選択肢 失業率 失業率:プラス1% -0.256 0.063 0.774 0.684 0.876 < .001
2選択肢 失業率 失業率:マイナス1% -0.064 0.065 0.938 0.825 1.066 .327
3選択肢 政権与党の政党名 立憲民主党 -0.543 0.089 0.581 0.488 0.691 < .001
3選択肢 政権与党の政党名 日本維新の会 -0.341 0.077 0.711 0.612 0.826 < .001
3選択肢 政権与党の政党名 公明党 -1.061 0.087 0.346 0.291 0.411 < .001
3選択肢 政権与党の政党名 国民民主党 -0.096 0.079 0.908 0.778 1.061 .224
3選択肢 政権与党の政党名 れいわ新選組 -1.121 0.100 0.326 0.268 0.396 < .001
3選択肢 政権与党の政党名 参政党 -0.487 0.084 0.614 0.521 0.725 < .001
3選択肢 政権与党の政党名 日本共産党 -1.226 0.103 0.293 0.240 0.359 < .001
3選択肢 政権与党の政党名 中道改革連合 -0.738 0.092 0.478 0.399 0.573 < .001
3選択肢 政権与党の政党名 チームみらい -0.322 0.081 0.725 0.618 0.850 < .001
3選択肢 GDP成長率 GDP:プラス1% 0.331 0.046 1.393 1.273 1.523 < .001
3選択肢 GDP成長率 GDP:マイナス1% -0.264 0.050 0.768 0.696 0.846 < .001
3選択肢 日経平均 日経平均:プラス1000円 0.157 0.048 1.170 1.066 1.285 < .001
3選択肢 日経平均 日経平均:マイナス1000円 -0.275 0.047 0.760 0.692 0.834 < .001
3選択肢 CPI CPI:プラス1ポイント -0.016 0.046 0.984 0.900 1.076 .725
3選択肢 CPI CPI:マイナス1ポイント -0.084 0.045 0.920 0.841 1.005 .065
3選択肢 失業率 失業率:プラス1% -0.224 0.047 0.799 0.729 0.876 < .001
3選択肢 失業率 失業率:マイナス1% -0.097 0.046 0.907 0.828 0.993 .035
4選択肢 政権与党の政党名 立憲民主党 -0.689 0.081 0.502 0.428 0.589 < .001
4選択肢 政権与党の政党名 日本維新の会 -0.362 0.068 0.696 0.609 0.795 < .001
4選択肢 政権与党の政党名 公明党 -1.181 0.085 0.307 0.260 0.363 < .001
4選択肢 政権与党の政党名 国民民主党 -0.186 0.068 0.830 0.726 0.949 .007
4選択肢 政権与党の政党名 れいわ新選組 -1.257 0.093 0.285 0.237 0.342 < .001
4選択肢 政権与党の政党名 参政党 -0.502 0.074 0.605 0.524 0.700 < .001
4選択肢 政権与党の政党名 日本共産党 -1.270 0.096 0.281 0.233 0.339 < .001
4選択肢 政権与党の政党名 中道改革連合 -0.783 0.086 0.457 0.386 0.542 < .001
4選択肢 政権与党の政党名 チームみらい -0.452 0.077 0.636 0.547 0.740 < .001
4選択肢 GDP成長率 GDP:プラス1% 0.271 0.041 1.311 1.209 1.421 < .001
4選択肢 GDP成長率 GDP:マイナス1% -0.205 0.043 0.814 0.748 0.887 < .001
4選択肢 日経平均 日経平均:プラス1000円 0.202 0.043 1.223 1.125 1.330 < .001
4選択肢 日経平均 日経平均:マイナス1000円 -0.211 0.043 0.810 0.744 0.881 < .001
4選択肢 CPI CPI:プラス1ポイント 0.037 0.041 1.038 0.958 1.124 .366
4選択肢 CPI CPI:マイナス1ポイント -0.061 0.042 0.941 0.867 1.021 .145
4選択肢 失業率 失業率:プラス1% -0.209 0.040 0.811 0.749 0.878 < .001
4選択肢 失業率 失業率:マイナス1% -0.116 0.041 0.890 0.822 0.964 .004
5選択肢 政権与党の政党名 立憲民主党 -0.598 0.074 0.550 0.476 0.636 < .001
5選択肢 政権与党の政党名 日本維新の会 -0.371 0.061 0.690 0.612 0.778 < .001
5選択肢 政権与党の政党名 公明党 -1.223 0.081 0.294 0.251 0.345 < .001
5選択肢 政権与党の政党名 国民民主党 -0.211 0.061 0.810 0.718 0.913 < .001
5選択肢 政権与党の政党名 れいわ新選組 -1.214 0.083 0.297 0.252 0.349 < .001
5選択肢 政権与党の政党名 参政党 -0.603 0.070 0.547 0.477 0.627 < .001
5選択肢 政権与党の政党名 日本共産党 -1.238 0.084 0.290 0.246 0.342 < .001
5選択肢 政権与党の政党名 中道改革連合 -0.822 0.076 0.439 0.379 0.510 < .001
5選択肢 政権与党の政党名 チームみらい -0.553 0.069 0.575 0.503 0.658 < .001
5選択肢 GDP成長率 GDP:プラス1% 0.340 0.037 1.404 1.307 1.509 < .001
5選択肢 GDP成長率 GDP:マイナス1% -0.155 0.037 0.857 0.796 0.922 < .001
5選択肢 日経平均 日経平均:プラス1000円 0.232 0.034 1.262 1.179 1.350 < .001
5選択肢 日経平均 日経平均:マイナス1000円 -0.152 0.037 0.859 0.799 0.923 < .001
5選択肢 CPI CPI:プラス1ポイント 0.028 0.035 1.028 0.961 1.101 .421
5選択肢 CPI CPI:マイナス1ポイント -0.007 0.037 0.993 0.925 1.067 .852
5選択肢 失業率 失業率:プラス1% -0.188 0.037 0.829 0.771 0.891 < .001
5選択肢 失業率 失業率:マイナス1% -0.051 0.035 0.951 0.887 1.019 .152

H. 政党支持による異質性

支持政党別AMCEでは、各条件に該当する回答者数が40人未満のセルは推定対象外としている。したがって、以下では insufficient_cell_n をNAのまま表示せず、推定可能であった支持政党×選択肢数条件のみを掲載する。

補図H1:支持政党別AMCE

補図H1は、支持政党によるAMCEの異質性を実験ごとに示す。可読性のため、結果は実験1・2・3に分け、1つのパネルを1つの支持政党に対応させる。縦軸には属性名と水準名を一体として表示し、同一の支持政党について各属性・水準の推定結果を上から順に確認できるようにした。点はAMCE、横線は95%信頼区間を示し、点の形で選択肢数条件を区別する。

対応表も実験ごとに分け、選択肢数条件を列方向に展開する。各セルは AMCE [95% CI](pp) を示し、回答者数は支持政党×選択肢数条件ごとの小表として別に示す。この形式により、同じ属性・水準について2・3・4・5選択肢条件を横方向に直接比較できる。表示表では情報を点推定値と95%信頼区間に集約し、p値を含む完全な係数表は各実験のCSV出力 table_party_support_amce.csv に保存する。

支持AMCE一覧 <- dplyr::bind_rows(
  party_support_amce_results$study1$subgroup_coefficients %>%
    dplyr::mutate(実験 = "実験1(2023年)", study_id = "study1"),
  party_support_amce_results$study2$subgroup_coefficients %>%
    dplyr::mutate(実験 = "実験2(2026年)", study_id = "study2"),
  party_support_amce_results$study3$subgroup_coefficients %>%
    dplyr::mutate(実験 = "実験3(2026年)", study_id = "study3")
) %>%
  dplyr::filter(
    status == "estimated",
    !is.na(term),
    term != "(Intercept)",
    !is.na(estimate)
  ) %>%
  dplyr::mutate(
    属性表示 = 属性日本語(attribute),
    条件表示 = purrr::map2_chr(party_n, study_id, 条件日本語),
    水準表示 = 水準日本語(term, label, attribute),
    表示項目 = paste0(属性表示, ":", 水準表示)
  )

補図H1作成 <- function(描画データ, 実験名) {
  項目順 <- 描画データ %>%
    dplyr::distinct(属性表示, 水準表示, 表示項目) %>%
    dplyr::pull(表示項目)

  条件順 <- 描画データ %>%
    dplyr::distinct(party_n, 条件表示) %>%
    dplyr::arrange(party_n) %>%
    dplyr::pull(条件表示)

  描画データ <- 描画データ %>%
    dplyr::mutate(
      表示項目 = factor(表示項目, levels = rev(項目順)),
      条件表示 = factor(条件表示, levels = 条件順)
    )

  dodge <- ggplot2::position_dodge(width = 0.52)

  ggplot2::ggplot(
    描画データ,
    ggplot2::aes(
      x = estimate_pp,
      y = 表示項目,
      shape = 条件表示
    )
  ) +
    ggplot2::geom_vline(
      xintercept = 0,
      linewidth = 0.45
    ) +
    ggplot2::geom_errorbarh(
      ggplot2::aes(
        xmin = conf.low_pp,
        xmax = conf.high_pp
      ),
      height = 0.12,
      position = dodge,
      linewidth = 0.55
    ) +
    ggplot2::geom_point(
      position = dodge,
      size = 2.25,
      fill = "white"
    ) +
    ggplot2::facet_wrap(
      ~ party_support_h,
      ncol = 2,
      scales = "free_y"
    ) +
    ggplot2::labs(
      title = 実験名,
      subtitle = "各パネルは支持政党別の推定結果。点はAMCE、横線は95%信頼区間。",
      x = "選択確率への効果(pp)",
      y = NULL,
      shape = "選択肢数条件",
      caption = "回答者数が40人未満の支持政党×選択肢数条件は推定対象外。"
    ) +
    ggplot2::theme_bw(base_size = 10.5) +
    ggplot2::theme(
      legend.position = "top",
      legend.justification = "center",
      panel.grid.minor = ggplot2::element_blank(),
      strip.background = ggplot2::element_rect(fill = "white"),
      strip.text = ggplot2::element_text(face = "bold", size = 10.5),
      axis.text.y = ggplot2::element_text(size = 8.6, color = "black"),
      axis.text.x = ggplot2::element_text(color = "black"),
      plot.title = ggplot2::element_text(face = "bold"),
      plot.subtitle = ggplot2::element_text(size = 9.5),
      plot.caption = ggplot2::element_text(hjust = 0, size = 8.5),
      panel.spacing = grid::unit(1.0, "lines")
    )
}

表H1作成 <- function(表データ) {
  支持順 <- unique(表データ$party_support_h)
  項目順 <- unique(表データ$表示項目)

  表データ %>%
    dplyr::mutate(
      支持政党 = factor(party_support_h, levels = 支持順),
      `属性・水準` = factor(表示項目, levels = 項目順),
      結果 = sprintf(
        "%.2f [%.2f, %.2f]",
        estimate_pp,
        conf.low_pp,
        conf.high_pp
      )
    ) %>%
    dplyr::select(
      支持政党,
      `属性・水準`,
      条件 = 条件表示,
      結果
    ) %>%
    tidyr::pivot_wider(
      names_from = 条件,
      values_from = 結果,
      values_fill = "—"
    ) %>%
    dplyr::arrange(支持政党, `属性・水準`) %>%
    dplyr::mutate(
      支持政党 = as.character(支持政党),
      `属性・水準` = as.character(`属性・水準`)
    )
}

表H1回答者数作成 <- function(表データ) {
  表データ %>%
    dplyr::distinct(
      支持政党 = party_support_h,
      条件 = 条件表示,
      回答者数 = n_ids
    ) %>%
    dplyr::mutate(回答者数 = as.character(回答者数)) %>%
    tidyr::pivot_wider(
      names_from = 条件,
      values_from = 回答者数,
      values_fill = "—"
    ) %>%
    dplyr::arrange(支持政党)
}

補図H1a:実験1(2023年)

実験1について、推定可能であった支持政党別にAMCEを示す。各パネル内では、同一の属性・水準について4つの政党数条件を比較できる。

H1_実験1 <- 支持AMCE一覧 %>%
  dplyr::filter(study_id == "study1")

補図H1a <- 補図H1作成(
  H1_実験1,
  "補図H1a:実験1(2023年)の支持政党別AMCE"
)
補図H1a

対応する回答者数とAMCEを以下に示す。AMCE表では、各条件の点推定値と95%信頼区間を1セルにまとめている。

表H1a回答者数 <- 表H1回答者数作成(H1_実験1)
knitr::kable(
  表H1a回答者数,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1a-1:実験1(2023年)の支持政党別回答者数"
)
表H1a-1:実験1(2023年)の支持政党別回答者数
支持政党 2政党条件 3政党条件 4政党条件 5政党条件
公明党 154 142 178 156
日本共産党 45 49 74 55
日本維新の会 407 429 402 386
立憲民主党 196 201 212 234
表H1a <- 表H1作成(H1_実験1)
knitr::kable(
  表H1a,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1a-2:実験1(2023年)の支持政党別AMCE[点推定値 [95% CI]、pp]"
)
表H1a-2:実験1(2023年)の支持政党別AMCE[点推定値 [95% CI]、pp]
支持政党 属性・水準 2政党条件 3政党条件 4政党条件 5政党条件
日本維新の会 政策位置:右派・保守的 -2.02 [-6.12, 2.09] -4.21 [-7.71, -0.72] -4.37 [-7.21, -1.52] -3.88 [-6.37, -1.39]
日本維新の会 政策位置:左派・革新的 -7.84 [-11.76, -3.91] -10.14 [-13.58, -6.70] -8.27 [-11.26, -5.29] -6.54 [-9.06, -4.01]
日本維新の会 与党/野党:与党 4.29 [1.09, 7.49] 5.53 [2.43, 8.63] 4.98 [2.12, 7.84] 6.28 [3.67, 8.90]
日本維新の会 GDP成長率:GDP:プラス1% 9.39 [5.46, 13.32] 7.02 [4.10, 9.94] 10.53 [7.92, 13.14] 7.61 [5.31, 9.92]
日本維新の会 GDP成長率:GDP:マイナス1% -2.10 [-5.83, 1.63] -3.60 [-6.23, -0.98] -1.39 [-3.60, 0.81] -2.84 [-4.83, -0.84]
日本維新の会 日経平均:日経平均:プラス1000円 9.57 [5.82, 13.32] 7.44 [4.50, 10.37] 3.01 [0.46, 5.56] 3.72 [1.63, 5.80]
日本維新の会 日経平均:日経平均:マイナス1000円 -2.55 [-6.29, 1.18] -2.52 [-5.45, 0.42] -4.61 [-6.85, -2.37] -4.94 [-6.79, -3.09]
日本維新の会 議席数:議席数:10~49 -0.21 [-4.87, 4.44] 5.13 [1.78, 8.47] 5.04 [2.43, 7.64] 3.23 [1.14, 5.32]
日本維新の会 議席数:議席数:50~99 3.66 [-1.21, 8.54] 9.66 [6.32, 13.00] 8.13 [5.40, 10.85] 7.38 [4.73, 10.03]
日本維新の会 議席数:議席数:100~199 8.60 [3.71, 13.49] 12.47 [8.39, 16.54] 11.98 [8.84, 15.12] 10.64 [7.43, 13.85]
日本維新の会 議席数:議席数:200以上 9.37 [4.45, 14.28] 12.65 [8.56, 16.73] 11.95 [8.28, 15.62] 9.46 [6.33, 12.60]
日本維新の会 CPI:CPI:プラス1ポイント -1.55 [-5.32, 2.23] 2.12 [-0.57, 4.81] 3.50 [1.04, 5.95] 0.36 [-1.63, 2.34]
日本維新の会 CPI:CPI:マイナス1ポイント -2.30 [-6.10, 1.50] 1.09 [-1.54, 3.72] 0.24 [-2.18, 2.65] -2.10 [-4.09, -0.10]
日本維新の会 失業率:失業率:プラス1% -6.14 [-10.03, -2.25] -3.68 [-6.55, -0.81] -3.93 [-6.34, -1.52] -3.18 [-5.29, -1.06]
日本維新の会 失業率:失業率:マイナス1% -4.70 [-8.54, -0.86] -0.08 [-2.96, 2.79] 0.28 [-2.14, 2.70] 0.63 [-1.46, 2.72]
立憲民主党 政策位置:右派・保守的 1.68 [-4.14, 7.50] -2.04 [-6.81, 2.74] -7.38 [-11.43, -3.33] -4.18 [-7.28, -1.07]
立憲民主党 政策位置:左派・革新的 -2.46 [-7.90, 2.97] -4.68 [-9.39, 0.03] -10.03 [-14.11, -5.95] -6.24 [-9.32, -3.16]
立憲民主党 与党/野党:与党 5.90 [0.91, 10.89] -0.95 [-5.23, 3.33] 4.58 [0.73, 8.43] 4.83 [1.73, 7.93]
立憲民主党 GDP成長率:GDP:プラス1% 4.26 [-1.15, 9.67] 7.79 [3.81, 11.77] 0.87 [-2.46, 4.21] 4.99 [2.25, 7.72]
立憲民主党 GDP成長率:GDP:マイナス1% -2.43 [-7.98, 3.12] -1.69 [-5.42, 2.05] -5.32 [-8.34, -2.31] -4.11 [-6.62, -1.60]
立憲民主党 日経平均:日経平均:プラス1000円 2.07 [-3.85, 7.99] 4.48 [0.23, 8.73] 6.86 [3.36, 10.36] 3.84 [1.11, 6.58]
立憲民主党 日経平均:日経平均:マイナス1000円 -9.22 [-14.88, -3.55] -6.24 [-10.44, -2.05] -4.88 [-8.01, -1.75] -3.32 [-5.76, -0.89]
立憲民主党 議席数:議席数:10~49 3.77 [-3.44, 10.98] 3.27 [-1.61, 8.14] 2.11 [-1.57, 5.78] 3.34 [0.72, 5.96]
立憲民主党 議席数:議席数:50~99 10.85 [3.95, 17.75] 8.47 [3.09, 13.85] 3.47 [-0.61, 7.55] 7.26 [3.51, 11.02]
立憲民主党 議席数:議席数:100~199 10.32 [3.13, 17.50] 12.99 [6.69, 19.30] 6.38 [1.53, 11.24] 7.71 [3.53, 11.89]
立憲民主党 議席数:議席数:200以上 13.65 [5.86, 21.43] 9.09 [2.89, 15.29] 9.05 [3.35, 14.74] 9.53 [5.05, 14.01]
立憲民主党 CPI:CPI:プラス1ポイント -1.68 [-7.12, 3.76] -1.44 [-5.77, 2.90] 1.12 [-2.05, 4.28] 1.41 [-1.22, 4.05]
立憲民主党 CPI:CPI:マイナス1ポイント -1.08 [-6.68, 4.51] -1.23 [-5.49, 3.03] 0.57 [-2.84, 3.97] -1.98 [-4.50, 0.53]
立憲民主党 失業率:失業率:プラス1% -3.16 [-8.35, 2.02] -0.91 [-5.22, 3.40] -1.99 [-5.29, 1.31] -1.46 [-4.13, 1.21]
立憲民主党 失業率:失業率:マイナス1% -3.36 [-8.86, 2.14] -0.88 [-5.27, 3.51] -1.42 [-4.71, 1.86] -0.30 [-2.96, 2.36]
公明党 政策位置:右派・保守的 -11.27 [-17.21, -5.32] -10.45 [-15.76, -5.13] -5.60 [-9.85, -1.34] -7.78 [-11.72, -3.85]
公明党 政策位置:左派・革新的 -14.02 [-21.01, -7.02] -13.15 [-18.79, -7.51] -6.01 [-10.21, -1.81] -9.00 [-12.70, -5.29]
公明党 与党/野党:与党 5.22 [-0.79, 11.23] 3.82 [-1.21, 8.85] 2.53 [-1.40, 6.45] 1.82 [-2.01, 5.66]
公明党 GDP成長率:GDP:プラス1% 10.04 [3.83, 16.26] 11.68 [7.20, 16.16] 6.66 [2.77, 10.54] 5.91 [2.47, 9.35]
公明党 GDP成長率:GDP:マイナス1% -3.03 [-9.39, 3.32] -1.12 [-5.81, 3.57] -5.15 [-8.79, -1.52] -3.67 [-6.41, -0.93]
公明党 日経平均:日経平均:プラス1000円 2.06 [-4.11, 8.23] 8.41 [3.59, 13.24] 1.06 [-2.43, 4.54] 3.17 [0.37, 5.97]
公明党 日経平均:日経平均:マイナス1000円 -8.74 [-14.57, -2.91] -3.61 [-8.08, 0.85] -5.31 [-8.66, -1.96] -5.07 [-8.07, -2.07]
公明党 議席数:議席数:10~49 6.80 [-1.14, 14.74] 2.23 [-3.79, 8.26] 3.24 [-0.67, 7.15] 5.32 [2.20, 8.43]
公明党 議席数:議席数:50~99 14.72 [6.81, 22.63] 6.69 [0.29, 13.10] 7.54 [3.01, 12.07] 9.88 [5.94, 13.83]
公明党 議席数:議席数:100~199 8.74 [0.57, 16.90] 9.11 [1.93, 16.29] 7.68 [2.78, 12.58] 10.58 [5.78, 15.38]
公明党 議席数:議席数:200以上 11.71 [3.24, 20.17] 9.84 [2.38, 17.31] 8.06 [2.60, 13.53] 13.12 [7.50, 18.73]
公明党 CPI:CPI:プラス1ポイント 3.63 [-2.61, 9.87] -1.42 [-5.87, 3.02] 4.33 [1.07, 7.58] 0.47 [-2.48, 3.43]
公明党 CPI:CPI:マイナス1ポイント 1.00 [-4.76, 6.76] -1.40 [-6.50, 3.70] 0.14 [-3.20, 3.48] 1.56 [-1.43, 4.56]
公明党 失業率:失業率:プラス1% -1.56 [-8.11, 5.00] -5.22 [-10.28, -0.15] -3.94 [-7.70, -0.18] -4.48 [-7.39, -1.56]
公明党 失業率:失業率:マイナス1% -0.09 [-6.46, 6.28] -8.89 [-13.97, -3.81] -1.53 [-5.08, 2.02] -0.34 [-3.66, 2.97]
日本共産党 政策位置:右派・保守的 7.15 [-3.36, 17.66] -8.37 [-17.89, 1.15] -4.96 [-11.98, 2.05] 0.84 [-5.37, 7.06]
日本共産党 政策位置:左派・革新的 -8.98 [-20.58, 2.61] -4.85 [-15.18, 5.48] -8.90 [-14.23, -3.57] -2.65 [-9.38, 4.08]
日本共産党 与党/野党:与党 4.30 [-6.01, 14.61] 3.83 [-4.13, 11.78] 4.73 [-1.08, 10.55] 5.33 [-1.85, 12.50]
日本共産党 GDP成長率:GDP:プラス1% 7.02 [-5.08, 19.13] 4.94 [-3.49, 13.38] 12.25 [6.63, 17.87] 6.32 [0.63, 12.00]
日本共産党 GDP成長率:GDP:マイナス1% -8.82 [-21.36, 3.72] -10.69 [-17.77, -3.62] -5.77 [-11.31, -0.24] -0.52 [-6.47, 5.43]
日本共産党 日経平均:日経平均:プラス1000円 10.03 [-2.67, 22.73] 0.91 [-7.89, 9.71] 1.20 [-4.60, 7.01] 3.33 [-3.10, 9.76]
日本共産党 日経平均:日経平均:マイナス1000円 -4.13 [-13.56, 5.29] -11.70 [-19.14, -4.26] -8.69 [-13.57, -3.80] -5.35 [-10.61, -0.10]
日本共産党 議席数:議席数:10~49 8.41 [-7.24, 24.06] -5.14 [-15.60, 5.33] 1.20 [-4.69, 7.09] 6.08 [0.91, 11.26]
日本共産党 議席数:議席数:50~99 12.54 [-2.61, 27.68] 6.40 [-3.36, 16.16] 5.10 [-1.82, 12.02] 13.52 [6.70, 20.34]
日本共産党 議席数:議席数:100~199 8.06 [-7.07, 23.20] 10.40 [0.91, 19.89] 13.55 [5.20, 21.90] 11.38 [4.33, 18.43]
日本共産党 議席数:議席数:200以上 4.37 [-10.39, 19.14] 14.57 [2.31, 26.84] 4.59 [-3.69, 12.88] 10.02 [2.10, 17.94]
日本共産党 CPI:CPI:プラス1ポイント 2.37 [-11.47, 16.21] 7.74 [-0.24, 15.73] 0.22 [-5.28, 5.72] 0.24 [-4.98, 5.46]
日本共産党 CPI:CPI:マイナス1ポイント 2.77 [-11.16, 16.70] 0.00 [-7.77, 7.78] -0.61 [-4.92, 3.70] -0.48 [-5.00, 4.04]
日本共産党 失業率:失業率:プラス1% -5.40 [-16.48, 5.67] 0.39 [-7.53, 8.30] -3.56 [-9.26, 2.14] -4.99 [-10.87, 0.90]
日本共産党 失業率:失業率:マイナス1% 3.38 [-9.03, 15.79] -0.21 [-8.41, 8.00] 1.82 [-3.54, 7.17] -3.39 [-8.66, 1.88]

補図H1b:実験2(2026年)

実験2についても同じ形式で示す。支持政党の種類が実験1より多いため、支持政党を2列のファセットに分け、各パネルで属性・水準を縦方向に追えるようにした。

H1_実験2 <- 支持AMCE一覧 %>%
  dplyr::filter(study_id == "study2")

補図H1b <- 補図H1作成(
  H1_実験2,
  "補図H1b:実験2(2026年)の支持政党別AMCE"
)
補図H1b

表H1b回答者数 <- 表H1回答者数作成(H1_実験2)
knitr::kable(
  表H1b回答者数,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1b-1:実験2(2026年)の支持政党別回答者数"
)
表H1b-1:実験2(2026年)の支持政党別回答者数
支持政党 2政党条件 3政党条件 4政党条件 5政党条件
チームみらい 42 50 61 76
参政党 41 47 63
国民民主党 42 73 62 76
支持政党なし 256 380 391 434
日本維新の会 45 66 58 67
立憲民主党 42 44 59
自由民主党 145 229 245 292
表H1b <- 表H1作成(H1_実験2)
knitr::kable(
  表H1b,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1b-2:実験2(2026年)の支持政党別AMCE[点推定値 [95% CI]、pp]"
)
表H1b-2:実験2(2026年)の支持政党別AMCE[点推定値 [95% CI]、pp]
支持政党 属性・水準 2政党条件 3政党条件 4政党条件 5政党条件
支持政党なし 政策位置:右派・保守的 -5.32 [-10.45, -0.19] -5.78 [-9.58, -1.98] -4.90 [-8.16, -1.63] -2.86 [-5.42, -0.30]
支持政党なし 政策位置:左派・革新的 -9.73 [-14.90, -4.57] -10.05 [-13.48, -6.63] -12.04 [-14.87, -9.22] -7.02 [-9.36, -4.69]
支持政党なし 与党/野党:与党 0.53 [-3.65, 4.71] -0.22 [-3.15, 2.70] 0.86 [-1.57, 3.28] 2.22 [0.35, 4.08]
支持政党なし GDP成長率:GDP:プラス1% 13.04 [8.25, 17.82] 7.34 [4.26, 10.42] 5.63 [3.19, 8.06] 6.25 [4.23, 8.27]
支持政党なし GDP成長率:GDP:マイナス1% -4.71 [-9.66, 0.24] -7.39 [-10.18, -4.60] -5.53 [-7.72, -3.33] -3.32 [-5.02, -1.62]
支持政党なし 日経平均:日経平均:プラス1000円 4.47 [-0.53, 9.47] 3.75 [0.47, 7.04] 3.53 [0.82, 6.23] 5.40 [3.39, 7.42]
支持政党なし 日経平均:日経平均:マイナス1000円 -6.79 [-11.90, -1.67] -5.07 [-8.21, -1.93] -7.19 [-9.52, -4.85] -3.53 [-5.42, -1.64]
支持政党なし 議席数:議席数:10~49 5.62 [-0.15, 11.39] 4.94 [1.13, 8.75] 5.15 [2.39, 7.91] 1.60 [-0.54, 3.74]
支持政党なし 議席数:議席数:50~99 3.90 [-1.78, 9.58] 9.72 [5.97, 13.46] 8.92 [5.99, 11.86] 5.34 [2.74, 7.94]
支持政党なし 議席数:議席数:100~199 8.74 [1.90, 15.58] 12.15 [8.13, 16.17] 11.13 [8.01, 14.24] 8.50 [5.92, 11.09]
支持政党なし 議席数:議席数:200以上 8.17 [1.87, 14.48] 11.60 [7.76, 15.43] 10.33 [7.06, 13.59] 8.48 [5.81, 11.15]
支持政党なし CPI:CPI:プラス1ポイント 2.97 [-1.82, 7.76] 1.71 [-1.24, 4.66] 2.73 [0.26, 5.19] -1.39 [-3.17, 0.40]
支持政党なし CPI:CPI:マイナス1ポイント 4.75 [0.14, 9.37] -1.38 [-4.56, 1.79] -0.11 [-2.29, 2.07] -0.66 [-2.60, 1.27]
支持政党なし 失業率:失業率:プラス1% -5.94 [-10.98, -0.89] -4.25 [-7.44, -1.05] -4.78 [-7.25, -2.30] -3.58 [-5.48, -1.68]
支持政党なし 失業率:失業率:マイナス1% -0.94 [-6.05, 4.18] -0.28 [-3.44, 2.87] 0.25 [-2.42, 2.91] -0.20 [-2.30, 1.90]
自由民主党 政策位置:右派・保守的 8.49 [1.93, 15.04] 10.25 [5.28, 15.22] 10.36 [6.36, 14.35] 11.35 [8.21, 14.50]
自由民主党 政策位置:左派・革新的 -14.32 [-20.62, -8.03] -10.94 [-15.34, -6.53] -8.94 [-12.08, -5.81] -5.16 [-7.53, -2.79]
自由民主党 与党/野党:与党 12.28 [6.77, 17.79] 14.94 [11.42, 18.45] 11.56 [8.79, 14.34] 10.70 [8.59, 12.81]
自由民主党 GDP成長率:GDP:プラス1% 4.20 [-2.37, 10.77] 6.41 [2.59, 10.22] 6.24 [3.11, 9.37] 5.43 [3.13, 7.72]
自由民主党 GDP成長率:GDP:マイナス1% -3.93 [-9.85, 1.98] -3.77 [-7.56, 0.01] -4.71 [-7.51, -1.91] -1.11 [-3.24, 1.03]
自由民主党 日経平均:日経平均:プラス1000円 5.58 [-0.54, 11.69] 3.74 [-0.07, 7.56] 4.59 [1.52, 7.66] 3.48 [1.18, 5.78]
自由民主党 日経平均:日経平均:マイナス1000円 -4.32 [-10.55, 1.90] -6.64 [-10.66, -2.62] -4.25 [-7.06, -1.45] -1.86 [-4.07, 0.36]
自由民主党 議席数:議席数:10~49 -7.17 [-15.36, 1.02] 1.49 [-3.27, 6.24] 3.28 [0.00, 6.56] 2.94 [0.45, 5.44]
自由民主党 議席数:議席数:50~99 0.90 [-6.68, 8.48] 6.90 [1.74, 12.05] 5.46 [1.82, 9.11] 7.67 [5.11, 10.23]
自由民主党 議席数:議席数:100~199 6.99 [-0.51, 14.49] 13.18 [8.35, 18.02] 14.22 [10.29, 18.14] 12.19 [9.35, 15.04]
自由民主党 議席数:議席数:200以上 9.20 [0.84, 17.56] 12.10 [6.78, 17.42] 15.83 [11.83, 19.83] 18.24 [15.07, 21.42]
自由民主党 CPI:CPI:プラス1ポイント 4.74 [-1.81, 11.28] 2.31 [-1.30, 5.91] 1.73 [-1.38, 4.84] 1.50 [-0.79, 3.79]
自由民主党 CPI:CPI:マイナス1ポイント 2.40 [-3.79, 8.59] -5.04 [-8.68, -1.41] -0.44 [-3.54, 2.66] 0.68 [-1.45, 2.81]
自由民主党 失業率:失業率:プラス1% -4.43 [-11.01, 2.14] -3.10 [-6.86, 0.66] -3.21 [-6.13, -0.29] -1.41 [-3.61, 0.78]
自由民主党 失業率:失業率:マイナス1% -7.10 [-13.45, -0.76] -1.47 [-5.37, 2.43] -0.93 [-4.01, 2.14] -0.66 [-2.91, 1.58]
国民民主党 政策位置:右派・保守的 -4.67 [-16.44, 7.11] 7.63 [-0.76, 16.02] 1.35 [-4.69, 7.39] 3.76 [-1.81, 9.34]
国民民主党 政策位置:左派・革新的 -7.60 [-22.25, 7.05] -8.67 [-16.07, -1.27] -7.07 [-14.65, 0.50] -4.19 [-9.26, 0.89]
国民民主党 与党/野党:与党 3.08 [-5.91, 12.07] 0.14 [-5.99, 6.27] 0.16 [-5.98, 6.30] 1.79 [-2.77, 6.35]
国民民主党 GDP成長率:GDP:プラス1% 14.78 [1.85, 27.71] 6.71 [-0.54, 13.96] 13.69 [7.15, 20.24] 6.22 [1.46, 10.97]
国民民主党 GDP成長率:GDP:マイナス1% -17.70 [-30.01, -5.40] -5.86 [-11.60, -0.12] -4.51 [-10.34, 1.32] -3.45 [-7.58, 0.68]
国民民主党 日経平均:日経平均:プラス1000円 1.74 [-9.48, 12.96] 3.55 [-4.53, 11.62] 2.87 [-3.72, 9.46] 8.04 [2.98, 13.09]
国民民主党 日経平均:日経平均:マイナス1000円 -5.52 [-17.80, 6.76] -11.10 [-18.38, -3.83] -0.67 [-6.89, 5.56] -4.12 [-8.28, 0.04]
国民民主党 議席数:議席数:10~49 -1.97 [-15.00, 11.05] 12.16 [4.35, 19.97] 7.31 [-0.05, 14.68] 7.29 [2.31, 12.28]
国民民主党 議席数:議席数:50~99 13.44 [0.04, 26.83] 11.24 [2.12, 20.35] 11.10 [4.23, 17.96] 16.48 [10.52, 22.43]
国民民主党 議席数:議席数:100~199 12.27 [-2.31, 26.85] 15.41 [7.03, 23.79] 12.42 [4.72, 20.12] 13.28 [6.78, 19.78]
国民民主党 議席数:議席数:200以上 -2.29 [-19.03, 14.45] 13.91 [5.64, 22.19] 8.34 [-0.34, 17.02] 8.22 [2.30, 14.14]
国民民主党 CPI:CPI:プラス1ポイント -1.87 [-13.90, 10.16] 3.97 [-4.22, 12.17] -1.85 [-7.98, 4.29] 0.55 [-3.70, 4.80]
国民民主党 CPI:CPI:マイナス1ポイント 4.08 [-7.08, 15.24] -1.03 [-9.02, 6.95] -2.61 [-9.58, 4.35] 1.46 [-2.75, 5.67]
国民民主党 失業率:失業率:プラス1% 1.08 [-12.09, 14.24] -4.10 [-11.45, 3.26] -6.77 [-13.58, 0.04] -1.00 [-5.42, 3.41]
国民民主党 失業率:失業率:マイナス1% -0.00 [-11.80, 11.79] 3.28 [-3.64, 10.20] -8.96 [-14.65, -3.28] -0.67 [-5.43, 4.09]
日本維新の会 政策位置:右派・保守的 10.02 [-3.12, 23.16] -5.26 [-13.72, 3.21] 7.51 [-0.56, 15.57] -0.22 [-6.58, 6.13]
日本維新の会 政策位置:左派・革新的 -0.35 [-12.27, 11.56] -8.33 [-16.28, -0.37] 1.10 [-6.48, 8.68] -2.90 [-9.21, 3.42]
日本維新の会 与党/野党:与党 3.60 [-5.19, 12.39] 2.05 [-5.39, 9.48] 5.57 [-0.19, 11.33] 9.28 [5.28, 13.29]
日本維新の会 GDP成長率:GDP:プラス1% 0.86 [-9.29, 11.02] 6.10 [-2.12, 14.32] 10.92 [3.72, 18.12] 0.34 [-4.83, 5.51]
日本維新の会 GDP成長率:GDP:マイナス1% -1.07 [-12.02, 9.89] -3.08 [-10.95, 4.78] -1.32 [-7.54, 4.90] -5.40 [-10.04, -0.76]
日本維新の会 日経平均:日経平均:プラス1000円 5.31 [-6.01, 16.63] 8.54 [1.06, 16.03] 0.57 [-5.99, 7.12] -0.42 [-5.54, 4.70]
日本維新の会 日経平均:日経平均:マイナス1000円 -16.57 [-26.80, -6.33] -7.06 [-13.16, -0.96] -2.72 [-9.37, 3.94] -4.23 [-8.92, 0.46]
日本維新の会 議席数:議席数:10~49 -8.42 [-23.38, 6.54] 2.90 [-6.92, 12.72] 3.27 [-4.52, 11.06] 1.30 [-3.85, 6.45]
日本維新の会 議席数:議席数:50~99 3.42 [-11.94, 18.77] 2.25 [-7.39, 11.90] 13.24 [5.10, 21.38] 4.45 [-1.38, 10.28]
日本維新の会 議席数:議席数:100~199 7.12 [-11.10, 25.34] 12.03 [2.19, 21.88] 13.63 [4.86, 22.39] 6.33 [-0.43, 13.09]
日本維新の会 議席数:議席数:200以上 10.35 [-6.59, 27.29] 9.51 [-1.06, 20.09] 13.38 [3.97, 22.79] 7.46 [1.17, 13.74]
日本維新の会 CPI:CPI:プラス1ポイント -1.17 [-10.32, 7.97] -0.23 [-7.17, 6.71] -0.69 [-5.69, 4.32] 1.94 [-2.87, 6.75]
日本維新の会 CPI:CPI:マイナス1ポイント -5.28 [-16.62, 6.06] -2.37 [-10.06, 5.32] -1.81 [-8.00, 4.38] 1.20 [-3.20, 5.61]
日本維新の会 失業率:失業率:プラス1% -0.40 [-11.05, 10.25] 0.35 [-6.12, 6.81] -6.22 [-12.37, -0.07] -3.05 [-8.01, 1.91]
日本維新の会 失業率:失業率:マイナス1% 4.27 [-6.11, 14.66] -5.57 [-12.45, 1.30] -2.02 [-9.66, 5.63] -0.44 [-6.76, 5.88]
チームみらい 政策位置:右派・保守的 -2.83 [-16.96, 11.30] 7.51 [-2.39, 17.41] -4.17 [-11.01, 2.67] -5.25 [-10.18, -0.32]
チームみらい 政策位置:左派・革新的 -23.88 [-36.67, -11.09] 1.71 [-7.07, 10.50] -0.97 [-8.67, 6.73] -3.89 [-9.49, 1.71]
チームみらい 与党/野党:与党 4.88 [-5.07, 14.83] 2.88 [-3.49, 9.26] -1.22 [-6.85, 4.41] -1.70 [-5.89, 2.49]
チームみらい GDP成長率:GDP:プラス1% 7.65 [-3.71, 19.01] 17.19 [7.90, 26.47] 4.91 [-0.63, 10.45] 7.69 [2.40, 12.97]
チームみらい GDP成長率:GDP:マイナス1% 0.42 [-10.48, 11.32] -9.27 [-17.38, -1.15] -5.31 [-11.66, 1.04] -3.11 [-7.73, 1.50]
チームみらい 日経平均:日経平均:プラス1000円 12.99 [0.23, 25.75] 7.78 [-1.94, 17.51] 2.96 [-4.00, 9.93] 6.49 [2.04, 10.95]
チームみらい 日経平均:日経平均:マイナス1000円 2.12 [-8.91, 13.16] -1.88 [-9.42, 5.65] -4.96 [-10.44, 0.52] -2.41 [-6.90, 2.07]
チームみらい 議席数:議席数:10~49 -13.36 [-29.33, 2.61] -2.48 [-11.56, 6.59] 5.08 [-1.67, 11.83] 4.74 [0.04, 9.43]
チームみらい 議席数:議席数:50~99 17.12 [2.17, 32.07] 3.76 [-5.38, 12.90] 14.46 [5.75, 23.17] 4.61 [-0.73, 9.96]
チームみらい 議席数:議席数:100~199 9.78 [-8.67, 28.23] 0.13 [-11.36, 11.61] 13.68 [5.16, 22.20] 11.66 [5.03, 18.28]
チームみらい 議席数:議席数:200以上 22.76 [6.96, 38.56] 7.46 [-4.10, 19.01] 16.06 [7.41, 24.72] 10.21 [3.45, 16.96]
チームみらい CPI:CPI:プラス1ポイント -0.44 [-9.71, 8.83] 2.73 [-4.71, 10.16] 1.39 [-4.61, 7.40] -1.29 [-6.00, 3.42]
チームみらい CPI:CPI:マイナス1ポイント -0.01 [-10.26, 10.25] -3.01 [-11.79, 5.77] 2.10 [-4.30, 8.49] -2.47 [-7.24, 2.31]
チームみらい 失業率:失業率:プラス1% -7.32 [-20.30, 5.66] -7.56 [-16.69, 1.57] -9.35 [-14.99, -3.71] -2.77 [-7.71, 2.18]
チームみらい 失業率:失業率:マイナス1% -3.36 [-16.07, 9.36] -6.96 [-14.87, 0.95] -0.71 [-7.99, 6.58] -2.29 [-6.92, 2.34]
参政党 政策位置:右派・保守的 8.98 [-2.54, 20.50] 21.91 [12.61, 31.20] 20.94 [13.55, 28.32]
参政党 政策位置:左派・革新的 -7.06 [-17.57, 3.44] -11.33 [-18.02, -4.63] -3.70 [-9.44, 2.04]
参政党 与党/野党:与党 5.16 [-4.17, 14.49] -2.06 [-8.23, 4.12] 2.20 [-2.37, 6.77]
参政党 GDP成長率:GDP:プラス1% -0.00 [-10.97, 10.96] 10.22 [4.18, 16.26] 2.38 [-2.88, 7.65]
参政党 GDP成長率:GDP:マイナス1% -11.63 [-20.54, -2.71] -1.82 [-8.18, 4.53] -6.06 [-10.65, -1.47]
参政党 日経平均:日経平均:プラス1000円 2.68 [-5.22, 10.58] 1.60 [-4.21, 7.40] 5.21 [0.27, 10.15]
参政党 日経平均:日経平均:マイナス1000円 -2.13 [-10.56, 6.30] -0.64 [-7.85, 6.57] -3.55 [-8.36, 1.25]
参政党 議席数:議席数:10~49 8.87 [-3.29, 21.02] 12.68 [3.95, 21.42] 0.35 [-5.18, 5.88]
参政党 議席数:議席数:50~99 7.89 [-5.55, 21.34] 2.86 [-7.19, 12.90] 7.64 [1.94, 13.34]
参政党 議席数:議席数:100~199 8.37 [-2.80, 19.55] 8.36 [0.40, 16.33] 13.52 [7.32, 19.72]
参政党 議席数:議席数:200以上 -1.16 [-11.62, 9.30] 5.56 [-3.43, 14.54] 7.42 [1.48, 13.36]
参政党 CPI:CPI:プラス1ポイント 2.03 [-8.17, 12.23] 3.02 [-4.33, 10.37] 0.74 [-3.50, 4.98]
参政党 CPI:CPI:マイナス1ポイント -1.31 [-9.19, 6.57] -6.90 [-13.39, -0.41] -1.75 [-5.54, 2.03]
参政党 失業率:失業率:プラス1% -8.95 [-18.92, 1.03] -6.11 [-12.84, 0.62] -0.64 [-4.91, 3.63]
参政党 失業率:失業率:マイナス1% -3.20 [-13.56, 7.16] -3.64 [-10.48, 3.20] 0.72 [-3.92, 5.36]
立憲民主党 政策位置:右派・保守的 -25.44 [-35.61, -15.27] -13.26 [-21.65, -4.86] -13.47 [-19.20, -7.75]
立憲民主党 政策位置:左派・革新的 -9.91 [-20.81, 0.99] -1.30 [-10.26, 7.66] -3.82 [-11.59, 3.95]
立憲民主党 与党/野党:与党 -21.18 [-30.32, -12.05] -16.42 [-23.36, -9.48] -10.36 [-15.77, -4.94]
立憲民主党 GDP成長率:GDP:プラス1% 0.55 [-8.17, 9.27] 7.34 [-0.65, 15.33] 3.01 [-3.02, 9.04]
立憲民主党 GDP成長率:GDP:マイナス1% -6.62 [-15.08, 1.84] -9.22 [-15.77, -2.67] -3.81 [-9.28, 1.65]
立憲民主党 日経平均:日経平均:プラス1000円 13.37 [4.33, 22.41] 5.53 [-1.70, 12.76] 2.26 [-2.21, 6.73]
立憲民主党 日経平均:日経平均:マイナス1000円 -1.75 [-11.65, 8.14] -3.39 [-9.74, 2.97] -4.68 [-9.05, -0.32]
立憲民主党 議席数:議席数:10~49 -0.02 [-13.33, 13.28] 1.61 [-8.16, 11.37] 2.79 [-2.83, 8.40]
立憲民主党 議席数:議席数:50~99 -0.54 [-11.64, 10.55] 3.62 [-6.49, 13.73] 15.37 [8.55, 22.20]
立憲民主党 議席数:議席数:100~199 -0.12 [-12.37, 12.13] 16.52 [5.89, 27.14] 18.38 [11.88, 24.88]
立憲民主党 議席数:議席数:200以上 2.50 [-8.03, 13.03] 15.37 [3.83, 26.91] 14.99 [8.86, 21.12]
立憲民主党 CPI:CPI:プラス1ポイント -1.53 [-10.59, 7.53] -5.12 [-12.63, 2.39] -0.85 [-5.52, 3.83]
立憲民主党 CPI:CPI:マイナス1ポイント 1.98 [-8.09, 12.04] -6.33 [-13.37, 0.70] -1.06 [-6.05, 3.93]
立憲民主党 失業率:失業率:プラス1% -14.23 [-23.21, -5.26] -2.82 [-10.02, 4.38] 1.73 [-3.15, 6.61]
立憲民主党 失業率:失業率:マイナス1% -1.25 [-11.04, 8.54] 4.26 [-1.50, 10.03] 4.48 [-1.21, 10.17]

補図H1c:実験3(2026年)

実験3では、政党属性が政党名として提示される。図の構成は実験1・2と揃え、支持政党ごとに、政党名および経済属性の各水準に対するAMCEを比較できるようにした。

H1_実験3 <- 支持AMCE一覧 %>%
  dplyr::filter(study_id == "study3")

補図H1c <- 補図H1作成(
  H1_実験3,
  "補図H1c:実験3(2026年)の支持政党別AMCE"
)
補図H1c

表H1c回答者数 <- 表H1回答者数作成(H1_実験3)
knitr::kable(
  表H1c回答者数,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1c-1:実験3(2026年)の支持政党別回答者数"
)
表H1c-1:実験3(2026年)の支持政党別回答者数
支持政党 2選択肢条件 3選択肢条件 4選択肢条件 5選択肢条件
チームみらい 51 67
参政党 46 42 52
国民民主党 49 76 70 91
支持政党なし 261 335 370 447
日本維新の会 46 64 60
立憲民主党 63
自由民主党 163 219 254 311
表H1c <- 表H1作成(H1_実験3)
knitr::kable(
  表H1c,
  format = "html",
  row.names = FALSE,
  table.attr = 'class="table table-condensed" style="font-size:90%;"',
  caption = "表H1c-2:実験3(2026年)の支持政党別AMCE[点推定値 [95% CI]、pp]"
)
表H1c-2:実験3(2026年)の支持政党別AMCE[点推定値 [95% CI]、pp]
支持政党 属性・水準 2選択肢条件 3選択肢条件 4選択肢条件 5選択肢条件
支持政党なし 政権与党の政党名:立憲民主党 0.74 [-9.09, 10.58] -4.79 [-11.87, 2.29] -9.12 [-15.28, -2.96] -1.85 [-6.48, 2.78]
支持政党なし 政権与党の政党名:日本維新の会 -10.06 [-19.64, -0.48] -5.74 [-12.08, 0.59] -9.50 [-14.98, -4.02] -3.09 [-7.45, 1.27]
支持政党なし 政権与党の政党名:公明党 -21.56 [-30.97, -12.15] -18.37 [-24.99, -11.75] -18.40 [-23.82, -12.98] -12.61 [-16.50, -8.72]
支持政党なし 政権与党の政党名:国民民主党 1.09 [-7.88, 10.05] 2.36 [-4.42, 9.14] 1.93 [-3.80, 7.65] 4.80 [0.21, 9.39]
支持政党なし 政権与党の政党名:れいわ新選組 -26.73 [-36.50, -16.96] -17.04 [-24.11, -9.97] -17.85 [-23.57, -12.12] -11.85 [-15.95, -7.76]
支持政党なし 政権与党の政党名:参政党 -11.28 [-20.49, -2.07] -11.58 [-18.31, -4.85] -10.52 [-16.29, -4.75] -4.16 [-8.49, 0.17]
支持政党なし 政権与党の政党名:日本共産党 -26.13 [-35.60, -16.65] -17.25 [-24.46, -10.03] -17.12 [-22.84, -11.40] -11.77 [-15.80, -7.75]
支持政党なし 政権与党の政党名:中道改革連合 -7.07 [-16.79, 2.65] -7.74 [-15.15, -0.34] -7.72 [-14.12, -1.33] -5.69 [-10.01, -1.36]
支持政党なし 政権与党の政党名:チームみらい -0.43 [-9.60, 8.74] -3.81 [-10.45, 2.83] -5.40 [-11.52, 0.71] 0.22 [-4.44, 4.89]
支持政党なし GDP成長率:GDP:プラス1% 12.93 [8.34, 17.53] 6.60 [3.32, 9.89] 6.12 [3.53, 8.71] 7.30 [5.31, 9.30]
支持政党なし GDP成長率:GDP:マイナス1% -1.81 [-6.51, 2.89] -7.01 [-10.16, -3.85] -3.47 [-5.90, -1.03] -3.64 [-5.37, -1.91]
支持政党なし 日経平均:日経平均:プラス1000円 2.95 [-1.44, 7.34] 4.26 [0.95, 7.56] 4.92 [2.25, 7.60] 5.75 [3.83, 7.67]
支持政党なし 日経平均:日経平均:マイナス1000円 -5.85 [-10.93, -0.77] -4.97 [-8.05, -1.89] -4.75 [-7.25, -2.24] -2.92 [-4.72, -1.13]
支持政党なし CPI:CPI:プラス1ポイント -2.01 [-6.72, 2.70] -0.30 [-3.52, 2.92] -0.88 [-3.26, 1.51] -0.07 [-1.90, 1.76]
支持政党なし CPI:CPI:マイナス1ポイント -0.97 [-5.59, 3.65] -2.28 [-5.45, 0.89] -4.47 [-6.86, -2.08] -1.44 [-3.38, 0.50]
支持政党なし 失業率:失業率:プラス1% -7.45 [-12.32, -2.58] -6.78 [-9.93, -3.63] -4.65 [-7.13, -2.16] -3.04 [-5.04, -1.04]
支持政党なし 失業率:失業率:マイナス1% -3.03 [-7.81, 1.75] -1.01 [-4.28, 2.26] -2.87 [-5.37, -0.36] -1.22 [-3.22, 0.79]
自由民主党 政権与党の政党名:立憲民主党 -35.30 [-46.48, -24.12] -46.59 [-54.80, -38.38] -47.57 [-54.70, -40.43] -53.57 [-59.43, -47.71]
自由民主党 政権与党の政党名:日本維新の会 -16.83 [-25.95, -7.71] -24.49 [-32.31, -16.68] -30.95 [-37.84, -24.06] -30.79 [-36.94, -24.63]
自由民主党 政権与党の政党名:公明党 -31.29 [-42.09, -20.49] -50.52 [-57.89, -43.15] -55.88 [-62.15, -49.61] -53.05 [-59.05, -47.05]
自由民主党 政権与党の政党名:国民民主党 -17.49 [-27.60, -7.39] -29.14 [-36.79, -21.48] -36.79 [-43.25, -30.34] -41.21 [-47.00, -35.41]
自由民主党 政権与党の政党名:れいわ新選組 -56.09 [-66.06, -46.11] -54.33 [-62.75, -45.90] -56.75 [-63.59, -49.91] -56.38 [-62.21, -50.55]
自由民主党 政権与党の政党名:参政党 -35.62 [-45.83, -25.41] -33.32 [-41.68, -24.96] -40.05 [-47.03, -33.06] -50.66 [-56.69, -44.63]
自由民主党 政権与党の政党名:日本共産党 -58.61 [-68.30, -48.92] -59.57 [-67.10, -52.05] -61.82 [-68.02, -55.62] -57.78 [-63.55, -52.00]
自由民主党 政権与党の政党名:中道改革連合 -38.53 [-49.49, -27.57] -52.07 [-59.96, -44.17] -54.80 [-61.67, -47.93] -55.26 [-61.09, -49.43]
自由民主党 政権与党の政党名:チームみらい -26.52 [-36.15, -16.89] -34.90 [-43.04, -26.75] -44.00 [-51.21, -36.78] -47.44 [-53.49, -41.39]
自由民主党 GDP成長率:GDP:プラス1% 8.28 [2.69, 13.87] 5.82 [2.38, 9.25] 4.12 [1.26, 6.97] 4.45 [2.32, 6.58]
自由民主党 GDP成長率:GDP:マイナス1% -3.23 [-8.67, 2.22] -5.21 [-9.17, -1.26] -3.47 [-6.25, -0.68] -0.66 [-2.49, 1.17]
自由民主党 日経平均:日経平均:プラス1000円 7.71 [2.22, 13.20] 3.19 [-0.74, 7.11] 3.35 [0.36, 6.34] 3.04 [0.91, 5.17]
自由民主党 日経平均:日経平均:マイナス1000円 -4.77 [-10.45, 0.91] -5.98 [-9.57, -2.39] -1.26 [-3.95, 1.43] -2.15 [-4.23, -0.07]
自由民主党 CPI:CPI:プラス1ポイント 0.33 [-5.12, 5.78] 1.43 [-2.09, 4.95] 1.08 [-1.79, 3.94] 1.18 [-0.74, 3.10]
自由民主党 CPI:CPI:マイナス1ポイント -2.90 [-8.42, 2.62] 0.44 [-3.27, 4.15] 0.26 [-2.39, 2.91] -0.03 [-1.98, 1.93]
自由民主党 失業率:失業率:プラス1% -6.54 [-12.52, -0.57] -3.98 [-7.61, -0.34] -2.52 [-5.13, 0.10] -0.10 [-2.10, 1.90]
自由民主党 失業率:失業率:マイナス1% -3.37 [-8.97, 2.24] -4.23 [-7.62, -0.84] -0.47 [-3.16, 2.23] -0.75 [-2.71, 1.22]
国民民主党 政権与党の政党名:立憲民主党 6.08 [-17.38, 29.54] -12.86 [-27.13, 1.41] -5.60 [-19.28, 8.07] -13.60 [-25.01, -2.19]
国民民主党 政権与党の政党名:日本維新の会 9.72 [-12.02, 31.47] -12.07 [-27.33, 3.19] 4.44 [-9.23, 18.12] -9.03 [-19.63, 1.56]
国民民主党 政権与党の政党名:公明党 -7.82 [-30.54, 14.90] -29.46 [-40.25, -18.68] -9.01 [-19.36, 1.35] -23.18 [-32.61, -13.75]
国民民主党 政権与党の政党名:国民民主党 25.68 [4.69, 46.68] 28.20 [14.82, 41.57] 40.51 [26.54, 54.48] 27.05 [15.13, 38.97]
国民民主党 政権与党の政党名:れいわ新選組 -21.96 [-46.38, 2.46] -25.26 [-36.79, -13.73] -21.76 [-32.24, -11.29] -21.73 [-31.88, -11.58]
国民民主党 政権与党の政党名:参政党 7.75 [-13.83, 29.32] -0.67 [-17.07, 15.74] -2.81 [-15.32, 9.70] -14.58 [-24.85, -4.31]
国民民主党 政権与党の政党名:日本共産党 -20.58 [-41.93, 0.77] -19.83 [-33.22, -6.43] -20.86 [-30.73, -10.99] -24.39 [-33.49, -15.29]
国民民主党 政権与党の政党名:中道改革連合 6.29 [-12.94, 25.51] -23.73 [-36.82, -10.65] -11.83 [-23.78, 0.13] -17.41 [-28.07, -6.75]
国民民主党 政権与党の政党名:チームみらい 21.97 [2.03, 41.92] 5.68 [-8.86, 20.22] 0.48 [-14.09, 15.05] -11.79 [-22.39, -1.18]
国民民主党 GDP成長率:GDP:プラス1% -2.73 [-11.95, 6.49] 10.68 [4.08, 17.28] 6.52 [-0.10, 13.13] 5.54 [0.83, 10.25]
国民民主党 GDP成長率:GDP:マイナス1% -10.99 [-21.40, -0.57] -1.80 [-7.92, 4.32] -5.53 [-10.67, -0.38] 0.41 [-3.24, 4.07]
国民民主党 日経平均:日経平均:プラス1000円 1.02 [-9.64, 11.68] 3.55 [-3.79, 10.89] 1.09 [-4.92, 7.11] 0.98 [-2.68, 4.63]
国民民主党 日経平均:日経平均:マイナス1000円 -5.45 [-16.73, 5.83] -2.26 [-9.46, 4.94] -4.25 [-9.30, 0.80] -3.44 [-6.57, -0.31]
国民民主党 CPI:CPI:プラス1ポイント -0.60 [-12.81, 11.61] 1.17 [-4.87, 7.21] 0.27 [-4.77, 5.32] 0.68 [-3.48, 4.84]
国民民主党 CPI:CPI:マイナス1ポイント -1.55 [-12.37, 9.26] 4.04 [-1.60, 9.69] 1.23 [-4.88, 7.35] 4.22 [0.34, 8.10]
国民民主党 失業率:失業率:プラス1% -3.54 [-13.05, 5.98] -6.22 [-13.09, 0.65] -1.05 [-5.89, 3.80] -2.38 [-5.88, 1.12]
国民民主党 失業率:失業率:マイナス1% -1.72 [-11.23, 7.80] -2.08 [-8.92, 4.75] 2.36 [-2.32, 7.04] 0.65 [-3.31, 4.61]
日本維新の会 政権与党の政党名:立憲民主党 -23.66 [-43.24, -4.08] -20.02 [-33.48, -6.57] -21.64 [-32.04, -11.24]
日本維新の会 政権与党の政党名:日本維新の会 18.89 [0.97, 36.80] 21.51 [6.23, 36.79] 35.33 [19.19, 51.48]
日本維新の会 政権与党の政党名:公明党 -36.32 [-53.85, -18.79] -22.15 [-35.20, -9.09] -22.37 [-32.76, -11.98]
日本維新の会 政権与党の政党名:国民民主党 -20.71 [-40.44, -0.98] -9.87 [-24.34, 4.60] -6.76 [-18.76, 5.25]
日本維新の会 政権与党の政党名:れいわ新選組 -45.42 [-61.49, -29.35] -22.65 [-35.00, -10.31] -14.15 [-26.23, -2.06]
日本維新の会 政権与党の政党名:参政党 -13.95 [-31.21, 3.31] -10.22 [-24.83, 4.39] -16.40 [-26.41, -6.40]
日本維新の会 政権与党の政党名:日本共産党 -40.77 [-57.04, -24.49] -27.21 [-39.61, -14.82] -21.59 [-31.75, -11.42]
日本維新の会 政権与党の政党名:中道改革連合 -34.64 [-54.04, -15.23] -18.34 [-33.65, -3.04] -15.87 [-28.04, -3.70]
日本維新の会 政権与党の政党名:チームみらい -8.52 [-29.27, 12.24] -7.07 [-20.54, 6.39] -7.28 [-20.35, 5.80]
日本維新の会 GDP成長率:GDP:プラス1% 5.13 [-2.27, 12.54] 8.34 [3.24, 13.43] 2.45 [-1.47, 6.37]
日本維新の会 GDP成長率:GDP:マイナス1% -5.35 [-13.02, 2.33] 2.95 [-2.72, 8.62] -6.55 [-10.87, -2.22]
日本維新の会 日経平均:日経平均:プラス1000円 4.91 [-4.27, 14.09] -3.11 [-10.64, 4.42] 2.14 [-2.61, 6.89]
日本維新の会 日経平均:日経平均:マイナス1000円 -7.38 [-15.22, 0.47] -7.98 [-13.94, -2.01] -2.23 [-6.47, 2.01]
日本維新の会 CPI:CPI:プラス1ポイント -2.65 [-11.05, 5.75] -2.66 [-8.07, 2.74] -0.44 [-4.92, 4.03]
日本維新の会 CPI:CPI:マイナス1ポイント -0.30 [-7.61, 7.01] 0.78 [-4.96, 6.51] 3.72 [-0.75, 8.18]
日本維新の会 失業率:失業率:プラス1% -2.34 [-10.83, 6.14] -4.58 [-10.19, 1.04] -0.27 [-5.98, 5.43]
日本維新の会 失業率:失業率:マイナス1% -1.90 [-9.41, 5.61] 1.46 [-4.78, 7.70] 2.56 [-1.60, 6.72]
チームみらい 政権与党の政党名:立憲民主党 -6.71 [-19.68, 6.26] 0.81 [-11.15, 12.76]
チームみらい 政権与党の政党名:日本維新の会 9.18 [-4.41, 22.77] -3.20 [-12.14, 5.75]
チームみらい 政権与党の政党名:公明党 -16.16 [-26.87, -5.45] -12.75 [-21.24, -4.27]
チームみらい 政権与党の政党名:国民民主党 1.21 [-11.62, 14.04] 3.82 [-5.60, 13.24]
チームみらい 政権与党の政党名:れいわ新選組 -18.02 [-29.24, -6.79] -13.33 [-22.00, -4.67]
チームみらい 政権与党の政党名:参政党 4.18 [-10.11, 18.46] -2.68 [-13.01, 7.64]
チームみらい 政権与党の政党名:日本共産党 -16.03 [-27.71, -4.36] -13.93 [-23.34, -4.52]
チームみらい 政権与党の政党名:中道改革連合 -13.19 [-25.56, -0.81] -4.76 [-15.38, 5.86]
チームみらい 政権与党の政党名:チームみらい 48.94 [35.13, 62.74] 37.67 [23.97, 51.37]
チームみらい GDP成長率:GDP:プラス1% 8.54 [1.61, 15.47] 9.10 [3.48, 14.71]
チームみらい GDP成長率:GDP:マイナス1% -3.19 [-9.18, 2.81] -4.16 [-8.90, 0.58]
チームみらい 日経平均:日経平均:プラス1000円 0.62 [-5.37, 6.62] 2.70 [-1.45, 6.85]
チームみらい 日経平均:日経平均:マイナス1000円 -3.43 [-9.65, 2.79] -3.20 [-7.11, 0.72]
チームみらい CPI:CPI:プラス1ポイント 2.78 [-3.70, 9.26] -3.34 [-7.59, 0.90]
チームみらい CPI:CPI:マイナス1ポイント -1.61 [-8.78, 5.55] -0.56 [-5.33, 4.21]
チームみらい 失業率:失業率:プラス1% -0.21 [-5.42, 4.99] -4.60 [-8.74, -0.46]
チームみらい 失業率:失業率:マイナス1% -1.80 [-7.78, 4.17] -0.08 [-4.33, 4.17]
参政党 政権与党の政党名:立憲民主党 -31.17 [-48.83, -13.51] -23.63 [-33.43, -13.82] -23.29 [-33.83, -12.76]
参政党 政権与党の政党名:日本維新の会 -8.75 [-25.57, 8.06] -4.13 [-15.54, 7.28] -11.14 [-21.99, -0.28]
参政党 政権与党の政党名:公明党 -29.26 [-45.87, -12.65] -17.96 [-30.38, -5.55] -27.02 [-36.77, -17.28]
参政党 政権与党の政党名:国民民主党 -14.78 [-34.48, 4.92] 15.24 [-1.44, 31.92] -6.82 [-19.94, 6.29]
参政党 政権与党の政党名:れいわ新選組 -35.49 [-53.20, -17.79] -18.05 [-31.32, -4.79] -22.87 [-33.73, -12.01]
参政党 政権与党の政党名:参政党 28.82 [14.23, 43.41] 52.99 [40.57, 65.42] 43.77 [29.78, 57.75]
参政党 政権与党の政党名:日本共産党 -43.09 [-59.59, -26.59] -21.44 [-33.47, -9.41] -23.24 [-34.51, -11.97]
参政党 政権与党の政党名:中道改革連合 -41.85 [-57.51, -26.20] -22.82 [-33.16, -12.48] -24.34 [-34.61, -14.07]
参政党 政権与党の政党名:チームみらい -17.61 [-35.44, 0.23] 2.83 [-12.16, 17.82] -15.39 [-27.36, -3.43]
参政党 GDP成長率:GDP:プラス1% 8.78 [1.61, 15.96] 4.79 [-3.30, 12.87] 3.01 [-2.78, 8.79]
参政党 GDP成長率:GDP:マイナス1% -6.46 [-13.58, 0.66] -5.66 [-12.64, 1.32] -2.31 [-6.76, 2.14]
参政党 日経平均:日経平均:プラス1000円 4.40 [-6.02, 14.82] 0.25 [-6.40, 6.91] 3.43 [-1.26, 8.12]
参政党 日経平均:日経平均:マイナス1000円 0.20 [-9.41, 9.82] -4.26 [-9.99, 1.47] 0.22 [-4.17, 4.60]
参政党 CPI:CPI:プラス1ポイント -0.78 [-8.29, 6.74] 3.49 [-2.11, 9.09] 1.40 [-3.09, 5.90]
参政党 CPI:CPI:マイナス1ポイント -4.56 [-10.79, 1.67] -0.07 [-6.57, 6.42] -1.81 [-6.65, 3.04]
参政党 失業率:失業率:プラス1% -1.84 [-9.72, 6.04] -0.63 [-6.03, 4.76] -0.26 [-5.25, 4.73]
参政党 失業率:失業率:マイナス1% -3.19 [-8.63, 2.24] -3.86 [-10.66, 2.95] 1.05 [-3.67, 5.77]
立憲民主党 政権与党の政党名:立憲民主党 42.48 [28.96, 56.00]
立憲民主党 政権与党の政党名:日本維新の会 -1.82 [-10.06, 6.41]
立憲民主党 政権与党の政党名:公明党 -4.14 [-11.47, 3.18]
立憲民主党 政権与党の政党名:国民民主党 14.88 [4.04, 25.72]
立憲民主党 政権与党の政党名:れいわ新選組 -2.95 [-10.04, 4.14]
立憲民主党 政権与党の政党名:参政党 -1.03 [-8.16, 6.10]
立憲民主党 政権与党の政党名:日本共産党 1.91 [-6.64, 10.45]
立憲民主党 政権与党の政党名:中道改革連合 15.25 [5.75, 24.75]
立憲民主党 政権与党の政党名:チームみらい -0.05 [-7.52, 7.43]
立憲民主党 GDP成長率:GDP:プラス1% 7.46 [2.35, 12.56]
立憲民主党 GDP成長率:GDP:マイナス1% -2.33 [-6.77, 2.12]
立憲民主党 日経平均:日経平均:プラス1000円 2.79 [-2.46, 8.03]
立憲民主党 日経平均:日経平均:マイナス1000円 -0.33 [-5.52, 4.87]
立憲民主党 CPI:CPI:プラス1ポイント -1.81 [-6.24, 2.62]
立憲民主党 CPI:CPI:マイナス1ポイント -0.72 [-4.91, 3.47]
立憲民主党 失業率:失業率:プラス1% -4.70 [-9.93, 0.53]
立憲民主党 失業率:失業率:マイナス1% -3.89 [-8.39, 0.61]

補図H2:支持政党別の手がかり重要度と相対比重

支持手がかり一覧 <- dplyr::bind_rows(
  party_support_relative_cue_results$study1$intervals %>% dplyr::mutate(実験 = "実験1(2023年)", study_id = "study1"),
  party_support_relative_cue_results$study2$intervals %>% dplyr::mutate(実験 = "実験2(2026年)", study_id = "study2"),
  party_support_relative_cue_results$study3$intervals %>% dplyr::mutate(実験 = "実験3(2026年)", study_id = "study3")
) %>%
  dplyr::mutate(
    条件 = purrr::map2_chr(party_n, study_id, 条件日本語),
    指標 = purrr::map2_chr(statistic, study_id, 統計量日本語),
    表示値 = dplyr::if_else(statistic == "relative_party_weight_pairwise", 100 * estimate, 100 * estimate),
    下限 = 100 * conf_low,
    上限 = 100 * conf_high,
    単位 = dplyr::if_else(statistic == "relative_party_weight_pairwise", "%", "pp")
  )

相対比重データ <- 支持手がかり一覧 %>%
  dplyr::filter(statistic == "relative_party_weight_pairwise") %>%
  dplyr::mutate(数値ラベル = sprintf("%.1f%%", 表示値))

for (実験名 in unique(相対比重データ$実験)) {
  描画データ <- 相対比重データ %>% dplyr::filter(実験 == 実験名)
<- ggplot2::ggplot(描画データ, ggplot2::aes(x = party_n, y = 表示値, group = party_support_h)) +
    ggplot2::geom_hline(yintercept = 50, linetype = "dashed", linewidth = 0.4) +
    ggplot2::geom_line(linewidth = 0.65) +
    ggplot2::geom_errorbar(ggplot2::aes(ymin = 下限, ymax = 上限), width = 0.08, linewidth = 0.45) +
    ggplot2::geom_label(ggplot2::aes(label = 数値ラベル), size = 3.0, label.size = 0, fill = "white") +
    ggplot2::facet_wrap(~ party_support_h, scales = "free_y") +
    ggplot2::scale_x_continuous(breaks = 2:5, labels = 条件日本語(2:5, ifelse(unique(描画データ$study_id) == "study3", "study3", "study1"))) +
    ggplot2::labs(x = NULL, y = "政党手がかり相対比重(%)", subtitle = 実験名) +
    ggplot2::theme_bw(base_size = 10) +
    ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
  print(図)
}

表H2 <- 支持手がかり一覧 %>%
  dplyr::transmute(
    実験,
    支持政党 = party_support_h,
    `条件・指標` = paste0(条件, ":", 指標),
    推定値 = round(表示値, 2),
    `95%CI下限` = round(下限, 2),
    `95%CI上限` = round(上限, 2),
    単位
  )
knitr::kable(表日本語(表H2), format = "html", row.names = FALSE, caption = "表H2:支持政党別の手がかり重要度と相対比重")
表H2:支持政党別の手がかり重要度と相対比重
実験 支持政党 条件・指標 推定値 95%CI下限 95%CI上限 単位
実験1(2023年) 日本維新の会 2政党条件:政党重要度 5.09 3.59 6.78 pp
実験1(2023年) 日本維新の会 2政党条件:経済重要度 5.41 4.47 6.90 pp
実験1(2023年) 日本維新の会 2政党条件:政党重要度(選択肢数調整済み) 10.17 7.18 13.57 pp
実験1(2023年) 日本維新の会 2政党条件:経済重要度(選択肢数調整済み) 10.82 8.93 13.79 pp
実験1(2023年) 日本維新の会 2政党条件:政党手がかり相対比重 48.44 38.23 57.41 %
実験1(2023年) 日本維新の会 3政党条件:政党重要度 6.19 4.83 7.84 pp
実験1(2023年) 日本維新の会 3政党条件:経済重要度 4.38 3.68 5.51 pp
実験1(2023年) 日本維新の会 3政党条件:政党重要度(選択肢数調整済み) 18.58 14.49 23.52 pp
実験1(2023年) 日本維新の会 3政党条件:経済重要度(選択肢数調整済み) 13.15 11.03 16.53 pp
実験1(2023年) 日本維新の会 3政党条件:政党手がかり相対比重 58.56 49.36 65.52 %
実験1(2023年) 日本維新の会 4政党条件:政党重要度 5.52 4.24 6.99 pp
実験1(2023年) 日本維新の会 4政党条件:経済重要度 4.48 3.85 5.42 pp
実験1(2023年) 日本維新の会 4政党条件:政党重要度(選択肢数調整済み) 22.07 16.95 27.95 pp
実験1(2023年) 日本維新の会 4政党条件:経済重要度(選択肢数調整済み) 17.92 15.42 21.66 pp
実験1(2023年) 日本維新の会 4政党条件:政党手がかり相対比重 55.19 47.29 62.14 %
実験1(2023年) 日本維新の会 5政党条件:政党重要度 5.44 4.24 6.68 pp
実験1(2023年) 日本維新の会 5政党条件:経済重要度 4.30 3.64 5.03 pp
実験1(2023年) 日本維新の会 5政党条件:政党重要度(選択肢数調整済み) 27.22 21.22 33.40 pp
実験1(2023年) 日本維新の会 5政党条件:経済重要度(選択肢数調整済み) 21.51 18.22 25.14 pp
実験1(2023年) 日本維新の会 5政党条件:政党手がかり相対比重 55.87 48.23 62.06 %
実験1(2023年) 立憲民主党 2政党条件:政党重要度 5.20 3.31 7.93 pp
実験1(2023年) 立憲民主党 2政党条件:経済重要度 3.83 2.96 6.14 pp
実験1(2023年) 立憲民主党 2政党条件:政党重要度(選択肢数調整済み) 10.41 6.62 15.85 pp
実験1(2023年) 立憲民主党 2政党条件:経済重要度(選択肢数調整済み) 7.66 5.92 12.27 pp
実験1(2023年) 立憲民主党 2政党条件:政党手がかり相対比重 57.60 39.96 67.43 %
実験1(2023年) 立憲民主党 3政党条件:政党重要度 3.40 2.49 5.81 pp
実験1(2023年) 立憲民主党 3政党条件:経済重要度 3.88 3.29 5.75 pp
実験1(2023年) 立憲民主党 3政党条件:政党重要度(選択肢数調整済み) 10.19 7.46 17.42 pp
実験1(2023年) 立憲民主党 3政党条件:経済重要度(選択肢数調整済み) 11.63 9.87 17.25 pp
実験1(2023年) 立憲民主党 3政党条件:政党手がかり相対比重 46.70 33.47 57.85 %
実験1(2023年) 立憲民主党 4政党条件:政党重要度 5.25 3.56 7.11 pp
実験1(2023年) 立憲民主党 4政党条件:経済重要度 3.42 2.92 4.93 pp
実験1(2023年) 立憲民主党 4政党条件:政党重要度(選択肢数調整済み) 21.00 14.25 28.46 pp
実験1(2023年) 立憲民主党 4政党条件:経済重要度(選択肢数調整済み) 13.69 11.70 19.73 pp
実験1(2023年) 立憲民主党 4政党条件:政党手がかり相対比重 60.54 46.06 68.15 %
実験1(2023年) 立憲民主党 5政党条件:政党重要度 4.58 3.37 6.02 pp
実験1(2023年) 立憲民主党 5政党条件:経済重要度 3.58 2.75 4.60 pp
実験1(2023年) 立憲民主党 5政党条件:政党重要度(選択肢数調整済み) 22.91 16.87 30.08 pp
実験1(2023年) 立憲民主党 5政党条件:経済重要度(選択肢数調整済み) 17.88 13.74 22.99 pp
実験1(2023年) 立憲民主党 5政党条件:政党手がかり相対比重 56.17 46.56 65.70 %
実験1(2023年) 公明党 2政党条件:政党重要度 7.42 4.97 10.33 pp
実験1(2023年) 公明党 2政党条件:経済重要度 4.92 4.05 7.50 pp
実験1(2023年) 公明党 2政党条件:政党重要度(選択肢数調整済み) 14.85 9.95 20.66 pp
実験1(2023年) 公明党 2政党条件:経済重要度(選択肢数調整済み) 9.85 8.11 15.00 pp
実験1(2023年) 公明党 2政党条件:政党手がかり相対比重 60.12 46.64 68.04 %
実験1(2023年) 公明党 3政党条件:政党重要度 5.86 4.17 8.22 pp
実験1(2023年) 公明党 3政党条件:経済重要度 5.92 4.96 7.76 pp
実験1(2023年) 公明党 3政党条件:政党重要度(選択肢数調整済み) 17.57 12.52 24.67 pp
実験1(2023年) 公明党 3政党条件:経済重要度(選択肢数調整済み) 17.75 14.87 23.27 pp
実験1(2023年) 公明党 3政党条件:政党手がかり相対比重 49.75 37.47 59.67 %
実験1(2023年) 公明党 4政党条件:政党重要度 3.72 2.51 5.81 pp
実験1(2023年) 公明党 4政党条件:経済重要度 4.23 3.13 5.75 pp
実験1(2023年) 公明党 4政党条件:政党重要度(選択肢数調整済み) 14.86 10.02 23.22 pp
実験1(2023年) 公明党 4政党条件:経済重要度(選択肢数調整済み) 16.91 12.52 22.98 pp
実験1(2023年) 公明党 4政党条件:政党手がかり相対比重 46.78 34.69 60.02 %
実験1(2023年) 公明党 5政党条件:政党重要度 4.60 3.50 6.53 pp
実験1(2023年) 公明党 5政党条件:経済重要度 4.08 3.42 5.36 pp
実験1(2023年) 公明党 5政党条件:政党重要度(選択肢数調整済み) 23.02 17.51 32.64 pp
実験1(2023年) 公明党 5政党条件:経済重要度(選択肢数調整済み) 20.38 17.09 26.80 pp
実験1(2023年) 公明党 5政党条件:政党手がかり相対比重 53.04 42.31 63.34 %
実験1(2023年) 日本共産党 2政党条件:政党重要度 6.39 4.56 11.78 pp
実験1(2023年) 日本共産党 2政党条件:経済重要度 6.23 4.76 11.78 pp
実験1(2023年) 日本共産党 2政党条件:政党重要度(選択肢数調整済み) 12.78 9.11 23.56 pp
実験1(2023年) 日本共産党 2政党条件:経済重要度(選択肢数調整済み) 12.46 9.52 23.57 pp
実験1(2023年) 日本共産党 2政党条件:政党手がかり相対比重 50.64 31.63 66.38 %
実験1(2023年) 日本共産党 3政党条件:政党重要度 6.34 4.27 10.29 pp
実験1(2023年) 日本共産党 3政党条件:経済重要度 6.85 5.14 10.57 pp
実験1(2023年) 日本共産党 3政党条件:政党重要度(選択肢数調整済み) 19.01 12.82 30.87 pp
実験1(2023年) 日本共産党 3政党条件:経済重要度(選択肢数調整済み) 20.55 15.42 31.71 pp
実験1(2023年) 日本共産党 3政党条件:政党手がかり相対比重 48.05 32.82 62.62 %
実験1(2023年) 日本共産党 4政党条件:政党重要度 5.39 3.49 8.70 pp
実験1(2023年) 日本共産党 4政党条件:経済重要度 5.99 4.48 8.79 pp
実験1(2023年) 日本共産党 4政党条件:政党重要度(選択肢数調整済み) 21.57 13.97 34.78 pp
実験1(2023年) 日本共産党 4政党条件:経済重要度(選択肢数調整済み) 23.95 17.93 35.14 pp
実験1(2023年) 日本共産党 4政党条件:政党手がかり相対比重 47.38 34.06 60.47 %
実験1(2023年) 日本共産党 5政党条件:政党重要度 4.81 3.03 8.47 pp
実験1(2023年) 日本共産党 5政党条件:経済重要度 3.57 2.82 5.89 pp
実験1(2023年) 日本共産党 5政党条件:政党重要度(選択肢数調整済み) 24.07 15.17 42.36 pp
実験1(2023年) 日本共産党 5政党条件:経済重要度(選択肢数調整済み) 17.84 14.10 29.45 pp
実験1(2023年) 日本共産党 5政党条件:政党手がかり相対比重 57.44 38.54 71.29 %
実験2(2026年) 支持政党なし 2政党条件:政党重要度 3.83 2.53 6.22 pp
実験2(2026年) 支持政党なし 2政党条件:経済重要度 6.22 5.02 7.93 pp
実験2(2026年) 支持政党なし 2政党条件:政党重要度(選択肢数調整済み) 7.66 5.07 12.44 pp
実験2(2026年) 支持政党なし 2政党条件:経済重要度(選択肢数調整済み) 12.43 10.04 15.86 pp
実験2(2026年) 支持政党なし 2政党条件:政党手がかり相対比重 38.12 27.09 50.95 %
実験2(2026年) 支持政党なし 3政党条件:政党重要度 4.33 3.62 5.92 pp
実験2(2026年) 支持政党なし 3政党条件:経済重要度 5.24 4.35 6.50 pp
実験2(2026年) 支持政党なし 3政党条件:政党重要度(選択肢数調整済み) 13.00 10.87 17.77 pp
実験2(2026年) 支持政党なし 3政党条件:経済重要度(選択肢数調整済み) 15.72 13.05 19.50 pp
実験2(2026年) 支持政党なし 3政党条件:政党手がかり相対比重 45.26 38.89 54.38 %
実験2(2026年) 支持政党なし 4政党条件:政党重要度 4.85 3.96 6.09 pp
実験2(2026年) 支持政党なし 4政党条件:経済重要度 4.84 4.07 5.71 pp
実験2(2026年) 支持政党なし 4政党条件:政党重要度(選択肢数調整済み) 19.42 15.85 24.34 pp
実験2(2026年) 支持政党なし 4政党条件:経済重要度(選択肢数調整済み) 19.37 16.26 22.83 pp
実験2(2026年) 支持政党なし 4政党条件:政党手がかり相対比重 50.06 43.40 57.04 %
実験2(2026年) 支持政党なし 5政党条件:政党重要度 3.91 2.98 4.87 pp
実験2(2026年) 支持政党なし 5政党条件:経済重要度 3.90 3.34 4.73 pp
実験2(2026年) 支持政党なし 5政党条件:政党重要度(選択肢数調整済み) 19.53 14.91 24.35 pp
実験2(2026年) 支持政党なし 5政党条件:経済重要度(選択肢数調整済み) 19.49 16.69 23.64 pp
実験2(2026年) 支持政党なし 5政党条件:政党手がかり相対比重 50.05 41.26 57.35 %
実験2(2026年) 自由民主党 2政党条件:政党重要度 11.95 9.31 14.87 pp
実験2(2026年) 自由民主党 2政党条件:経済重要度 4.99 3.53 7.23 pp
実験2(2026年) 自由民主党 2政党条件:政党重要度(選択肢数調整済み) 23.89 18.62 29.73 pp
実験2(2026年) 自由民主党 2政党条件:経済重要度(選択肢数調整済み) 9.98 7.05 14.46 pp
実験2(2026年) 自由民主党 2政党条件:政党手がかり相対比重 70.53 60.77 78.71 %
実験2(2026年) 自由民主党 3政党条件:政党重要度 11.71 9.95 13.43 pp
実験2(2026年) 自由民主党 3政党条件:経済重要度 5.18 3.88 6.75 pp
実験2(2026年) 自由民主党 3政党条件:政党重要度(選択肢数調整済み) 35.13 29.86 40.30 pp
実験2(2026年) 自由民主党 3政党条件:経済重要度(選択肢数調整済み) 15.53 11.64 20.25 pp
実験2(2026年) 自由民主党 3政党条件:政党手がかり相対比重 69.35 61.89 76.20 %
実験2(2026年) 自由民主党 4政党条件:政党重要度 10.84 9.30 12.34 pp
実験2(2026年) 自由民主党 4政党条件:経済重要度 3.96 3.20 5.18 pp
実験2(2026年) 自由民主党 4政党条件:政党重要度(選択肢数調整済み) 43.36 37.21 49.37 pp
実験2(2026年) 自由民主党 4政党条件:経済重要度(選択肢数調整済み) 15.84 12.80 20.74 pp
実験2(2026年) 自由民主党 4政党条件:政党手がかり相対比重 73.24 65.54 78.08 %
実験2(2026年) 自由民主党 5政党条件:政党重要度 10.62 9.61 11.74 pp
実験2(2026年) 自由民主党 5政党条件:経済重要度 2.40 1.90 3.27 pp
実験2(2026年) 自由民主党 5政党条件:政党重要度(選択肢数調整済み) 53.11 48.05 58.72 pp
実験2(2026年) 自由民主党 5政党条件:経済重要度(選択肢数調整済み) 12.00 9.52 16.35 pp
実験2(2026年) 自由民主党 5政党条件:政党手がかり相対比重 81.57 75.95 85.34 %
実験2(2026年) 国民民主党 2政党条件:政党重要度 5.66 4.06 12.30 pp
実験2(2026年) 国民民主党 2政党条件:経済重要度 8.46 6.45 13.94 pp
実験2(2026年) 国民民主党 2政党条件:政党重要度(選択肢数調整済み) 11.33 8.11 24.60 pp
実験2(2026年) 国民民主党 2政党条件:経済重要度(選択肢数調整済み) 16.93 12.89 27.87 pp
実験2(2026年) 国民民主党 2政党条件:政党手がかり相対比重 40.09 27.47 59.50 %
実験2(2026年) 国民民主党 3政党条件:政党重要度 6.22 4.94 9.76 pp
実験2(2026年) 国民民主党 3政党条件:経済重要度 6.91 5.32 9.75 pp
実験2(2026年) 国民民主党 3政党条件:政党重要度(選択肢数調整済み) 18.65 14.83 29.28 pp
実験2(2026年) 国民民主党 3政党条件:経済重要度(選択肢数調整済み) 20.74 15.96 29.24 pp
実験2(2026年) 国民民主党 3政党条件:政党手がかり相対比重 47.34 38.02 60.40 %
実験2(2026年) 国民民主党 4政党条件:政党重要度 3.98 2.94 7.73 pp
実験2(2026年) 国民民主党 4政党条件:経済重要度 5.50 4.46 8.17 pp
実験2(2026年) 国民民主党 4政党条件:政党重要度(選択肢数調整済み) 15.94 11.76 30.91 pp
実験2(2026年) 国民民主党 4政党条件:経済重要度(選択肢数調整済み) 22.01 17.82 32.68 pp
実験2(2026年) 国民民主党 4政党条件:政党手がかり相対比重 42.00 31.79 58.16 %
実験2(2026年) 国民民主党 5政党条件:政党重要度 5.02 3.68 7.36 pp
実験2(2026年) 国民民主党 5政党条件:経済重要度 4.19 3.36 6.32 pp
実験2(2026年) 国民民主党 5政党条件:政党重要度(選択肢数調整済み) 25.11 18.42 36.81 pp
実験2(2026年) 国民民主党 5政党条件:経済重要度(選択肢数調整済み) 20.95 16.82 31.60 pp
実験2(2026年) 国民民主党 5政党条件:政党手がかり相対比重 54.51 40.84 65.60 %
実験2(2026年) 日本維新の会 2政党条件:政党重要度 6.99 4.19 12.61 pp
実験2(2026年) 日本維新の会 2政党条件:経済重要度 5.86 4.48 10.95 pp
実験2(2026年) 日本維新の会 2政党条件:政党重要度(選択肢数調整済み) 13.98 8.38 25.22 pp
実験2(2026年) 日本維新の会 2政党条件:経済重要度(選択肢数調整済み) 11.73 8.95 21.90 pp
実験2(2026年) 日本維新の会 2政党条件:政党手がかり相対比重 54.38 36.28 65.23 %
実験2(2026年) 日本維新の会 3政党条件:政党重要度 4.58 3.07 8.58 pp
実験2(2026年) 日本維新の会 3政党条件:経済重要度 5.69 4.53 8.49 pp
実験2(2026年) 日本維新の会 3政党条件:政党重要度(選択肢数調整済み) 13.74 9.20 25.75 pp
実験2(2026年) 日本維新の会 3政党条件:経済重要度(選択肢数調整済み) 17.06 13.60 25.48 pp
実験2(2026年) 日本維新の会 3政党条件:政党手がかり相対比重 44.60 30.75 59.88 %
実験2(2026年) 日本維新の会 4政党条件:政党重要度 6.29 4.16 10.00 pp
実験2(2026年) 日本維新の会 4政党条件:経済重要度 4.11 3.14 7.15 pp
実験2(2026年) 日本維新の会 4政党条件:政党重要度(選択肢数調整済み) 25.16 16.64 39.99 pp
実験2(2026年) 日本維新の会 4政党条件:経済重要度(選択肢数調整済み) 16.45 12.58 28.59 pp
実験2(2026年) 日本維新の会 4政党条件:政党手がかり相対比重 60.46 42.10 72.36 %
実験2(2026年) 日本維新の会 5政党条件:政党重要度 5.28 3.88 7.83 pp
実験2(2026年) 日本維新の会 5政党条件:経済重要度 2.56 2.06 4.94 pp
実験2(2026年) 日本維新の会 5政党条件:政党重要度(選択肢数調整済み) 26.39 19.38 39.16 pp
実験2(2026年) 日本維新の会 5政党条件:経済重要度(選択肢数調整済み) 12.79 10.31 24.70 pp
実験2(2026年) 日本維新の会 5政党条件:政党手がかり相対比重 67.36 51.12 76.48 %
実験2(2026年) チームみらい 2政党条件:政党重要度 12.13 9.48 17.24 pp
実験2(2026年) チームみらい 2政党条件:経済重要度 5.89 4.43 11.21 pp
実験2(2026年) チームみらい 2政党条件:政党重要度(選択肢数調整済み) 24.27 18.95 34.47 pp
実験2(2026年) チームみらい 2政党条件:経済重要度(選択肢数調整済み) 11.78 8.86 22.41 pp
実験2(2026年) チームみらい 2政党条件:政党手がかり相対比重 67.32 51.58 76.76 %
実験2(2026年) チームみらい 3政党条件:政党重要度 2.76 2.42 7.43 pp
実験2(2026年) チームみらい 3政党条件:経済重要度 7.71 5.93 11.02 pp
実験2(2026年) チームみらい 3政党条件:政党重要度(選択肢数調整済み) 8.28 7.27 22.29 pp
実験2(2026年) チームみらい 3政党条件:経済重要度(選択肢数調整済み) 23.13 17.78 33.07 pp
実験2(2026年) チームみらい 3政党条件:政党手がかり相対比重 26.35 20.72 50.97 %
実験2(2026年) チームみらい 4政党条件:政党重要度 4.06 3.43 7.56 pp
実験2(2026年) チームみらい 4政党条件:経済重要度 4.97 3.60 7.89 pp
実験2(2026年) チームみらい 4政党条件:政党重要度(選択肢数調整済み) 16.23 13.74 30.24 pp
実験2(2026年) チームみらい 4政党条件:経済重要度(選択肢数調整済み) 19.86 14.41 31.56 pp
実験2(2026年) チームみらい 4政党条件:政党手がかり相対比重 44.96 36.39 63.14 %
実験2(2026年) チームみらい 5政党条件:政党重要度 3.80 2.63 5.99 pp
実験2(2026年) チームみらい 5政党条件:経済重要度 3.92 2.86 6.21 pp
実験2(2026年) チームみらい 5政党条件:政党重要度(選択肢数調整済み) 18.98 13.16 29.96 pp
実験2(2026年) チームみらい 5政党条件:経済重要度(選択肢数調整済み) 19.62 14.29 31.07 pp
実験2(2026年) チームみらい 5政党条件:政党手がかり相対比重 49.17 33.67 61.87 %
実験3(2026年) 支持政党なし 2選択肢条件:政党名重要度 12.75 10.83 15.93 pp
実験3(2026年) 支持政党なし 2選択肢条件:経済重要度 5.38 4.23 7.47 pp
実験3(2026年) 支持政党なし 2選択肢条件:政党名重要度(選択肢数調整済み) 25.49 21.66 31.87 pp
実験3(2026年) 支持政党なし 2選択肢条件:経済重要度(選択肢数調整済み) 10.76 8.47 14.93 pp
実験3(2026年) 支持政党なし 2選択肢条件:政党手がかり相対比重 70.32 62.45 77.48 %
実験3(2026年) 支持政党なし 3選択肢条件:政党名重要度 8.88 7.27 11.32 pp
実験3(2026年) 支持政党なし 3選択肢条件:経済重要度 5.34 4.46 6.49 pp
実験3(2026年) 支持政党なし 3選択肢条件:政党名重要度(選択肢数調整済み) 26.63 21.82 33.95 pp
実験3(2026年) 支持政党なし 3選択肢条件:経済重要度(選択肢数調整済み) 16.01 13.38 19.46 pp
実験3(2026年) 支持政党なし 3選択肢条件:政党手がかり相対比重 62.46 55.62 69.13 %
実験3(2026年) 支持政党なし 4選択肢条件:政党名重要度 8.31 7.00 10.19 pp
実験3(2026年) 支持政党なし 4選択肢条件:経済重要度 4.77 3.96 5.78 pp
実験3(2026年) 支持政党なし 4選択肢条件:政党名重要度(選択肢数調整済み) 33.24 27.99 40.76 pp
実験3(2026年) 支持政党なし 4選択肢条件:経済重要度(選択肢数調整済み) 19.09 15.84 23.12 pp
実験3(2026年) 支持政党なし 4選択肢条件:政党手がかり相対比重 63.52 57.46 70.08 %
実験3(2026年) 支持政党なし 5選択肢条件:政党名重要度 7.05 6.04 8.37 pp
実験3(2026年) 支持政党なし 5選択肢条件:経済重要度 4.04 3.47 4.74 pp
実験3(2026年) 支持政党なし 5選択肢条件:政党名重要度(選択肢数調整済み) 35.27 30.22 41.84 pp
実験3(2026年) 支持政党なし 5選択肢条件:経済重要度(選択肢数調整済み) 20.19 17.35 23.71 pp
実験3(2026年) 支持政党なし 5選択肢条件:政党手がかり相対比重 63.60 58.13 69.15 %
実験3(2026年) 自由民主党 2選択肢条件:政党名重要度 20.69 17.88 24.62 pp
実験3(2026年) 自由民主党 2選択肢条件:経済重要度 5.70 4.22 7.54 pp
実験3(2026年) 自由民主党 2選択肢条件:政党名重要度(選択肢数調整済み) 41.38 35.75 49.24 pp
実験3(2026年) 自由民主党 2選択肢条件:経済重要度(選択肢数調整済み) 11.40 8.44 15.08 pp
実験3(2026年) 自由民主党 2選択肢条件:政党手がかり相対比重 78.40 72.05 84.06 %
実験3(2026年) 自由民主党 3選択肢条件:政党名重要度 20.57 17.85 23.03 pp
実験3(2026年) 自由民主党 3選択肢条件:経済重要度 4.48 3.55 6.23 pp
実験3(2026年) 自由民主党 3選択肢条件:政党名重要度(選択肢数調整済み) 61.71 53.54 69.10 pp
実験3(2026年) 自由民主党 3選択肢条件:経済重要度(選択肢数調整済み) 13.44 10.64 18.68 pp
実験3(2026年) 自由民主党 3選択肢条件:政党手がかり相対比重 82.12 75.41 85.88 %
実験3(2026年) 自由民主党 4選択肢条件:政党名重要度 19.66 17.72 21.53 pp
実験3(2026年) 自由民主党 4選択肢条件:経済重要度 2.91 2.30 4.26 pp
実験3(2026年) 自由民主党 4選択肢条件:政党名重要度(選択肢数調整済み) 78.63 70.87 86.13 pp
実験3(2026年) 自由民主党 4選択肢条件:経済重要度(選択肢数調整済み) 11.63 9.20 17.05 pp
実験3(2026年) 自由民主党 4選択肢条件:政党手がかり相対比重 87.11 81.82 89.73 %
実験3(2026年) 自由民主党 5選択肢条件:政党名重要度 17.57 16.08 19.23 pp
実験3(2026年) 自由民主党 5選択肢条件:経済重要度 2.33 1.78 3.22 pp
実験3(2026年) 自由民主党 5選択肢条件:政党名重要度(選択肢数調整済み) 87.87 80.41 96.13 pp
実験3(2026年) 自由民主党 5選択肢条件:経済重要度(選択肢数調整済み) 11.64 8.92 16.08 pp
実験3(2026年) 自由民主党 5選択肢条件:政党手がかり相対比重 88.30 84.32 90.95 %
実験3(2026年) 国民民主党 2選択肢条件:政党名重要度 18.98 14.97 26.31 pp
実験3(2026年) 国民民主党 2選択肢条件:経済重要度 4.32 3.47 9.09 pp
実験3(2026年) 国民民主党 2選択肢条件:政党名重要度(選択肢数調整済み) 37.96 29.93 52.62 pp
実験3(2026年) 国民民主党 2選択肢条件:経済重要度(選択肢数調整済み) 8.64 6.93 18.17 pp
実験3(2026年) 国民民主党 2選択肢条件:政党手がかり相対比重 81.46 67.84 86.08 %
実験3(2026年) 国民民主党 3選択肢条件:政党名重要度 20.20 16.30 24.53 pp
実験3(2026年) 国民民主党 3選択肢条件:経済重要度 4.36 3.16 7.22 pp
実験3(2026年) 国民民主党 3選択肢条件:政党名重要度(選択肢数調整済み) 60.59 48.89 73.59 pp
実験3(2026年) 国民民主党 3選択肢条件:経済重要度(選択肢数調整済み) 13.09 9.49 21.67 pp
実験3(2026年) 国民民主党 3選択肢条件:政党手がかり相対比重 82.23 71.68 87.02 %
実験3(2026年) 国民民主党 4選択肢条件:政党名重要度 18.43 16.01 22.51 pp
実験3(2026年) 国民民主党 4選択肢条件:経済重要度 3.81 2.92 6.42 pp
実験3(2026年) 国民民主党 4選択肢条件:政党名重要度(選択肢数調整済み) 73.73 64.04 90.02 pp
実験3(2026年) 国民民主党 4選択肢条件:経済重要度(選択肢数調整済み) 15.25 11.69 25.66 pp
実験3(2026年) 国民民主党 4選択肢条件:政党手がかり相対比重 82.86 73.39 86.89 %
実験3(2026年) 国民民主党 5選択肢条件:政党名重要度 15.75 13.01 19.17 pp
実験3(2026年) 国民民主党 5選択肢条件:経済重要度 3.05 2.20 4.78 pp
実験3(2026年) 国民民主党 5選択肢条件:政党名重要度(選択肢数調整済み) 78.73 65.05 95.85 pp
実験3(2026年) 国民民主党 5選択肢条件:経済重要度(選択肢数調整済み) 15.27 11.01 23.88 pp
実験3(2026年) 国民民主党 5選択肢条件:政党手がかり相対比重 83.75 75.55 88.48 %

補図H3:対象となる支持政党別の一致効果

一致効果 <- study3_all_party_match_results$coefficients %>%
  dplyr::filter(status == "estimated", !is.na(estimate)) %>%
  dplyr::mutate(
    条件 = 条件日本語(party_n, "study3"),
    数値ラベル = sprintf("%.1f", estimate_pp)
  )

補図H3 <- ggplot2::ggplot(一致効果, ggplot2::aes(x = party_n, y = estimate_pp, group = 1)) +
  ggplot2::geom_hline(yintercept = 0, linewidth = 0.4) +
  ggplot2::geom_line(linewidth = 0.65) +
  ggplot2::geom_errorbar(ggplot2::aes(ymin = conf.low_pp, ymax = conf.high_pp), width = 0.08, linewidth = 0.45) +
  ggplot2::geom_label(ggplot2::aes(label = 数値ラベル), size = 3.0, label.size = 0, fill = "white") +
  ggplot2::facet_wrap(~ support_party_valid) +
  ggplot2::scale_x_continuous(breaks = 2:5, labels = paste0(2:5, "選択肢")) +
  ggplot2::labs(x = "選択肢数", y = "一致効果(pp)") +
  ggplot2::theme_bw(base_size = 10) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
補図H3

表H3 <- 一致効果 %>%
  dplyr::transmute(
    支持政党 = support_party_valid,
    条件,
    回答者数 = n_ids,
    `一致効果(pp)` = round(estimate_pp, 2),
    `95%CI下限` = round(conf.low_pp, 2),
    `95%CI上限` = round(conf.high_pp, 2),
    p値 = signif(p.value, 3)
  )
knitr::kable(表日本語(表H3), format = "html", row.names = FALSE)
支持政党 条件 回答者数 一致効果(pp) 95%CI下限 95%CI上限 p値
自由民主党 2選択肢条件 163 34.77 28.06 41.49 0.00000000000000000048599999999999995625374338281687869
自由民主党 3選択肢条件 219 42.74 36.61 48.87 0.00000000000000000000000000000037699999999999995606639
自由民主党 4選択肢条件 254 47.62 41.97 53.28 0.00000000000000000000000000000000000000000476000000000
自由民主党 5選択肢条件 311 49.55 44.26 54.84 0.00000000000000000000000000000000000000000000000000197
国民民主党 2選択肢条件 49 25.26 8.98 41.53 0.00379999999999999999236721670570204878458753228187561
国民民主党 3選択肢条件 76 41.28 30.79 51.76 0.00000000004140000000000000050619231029003231014939956
国民民主党 4選択肢条件 70 48.40 37.40 59.40 0.00000000000143999999999999992264000658881428762470023
国民民主党 5選択肢条件 91 42.08 32.42 51.74 0.00000000000031500000000000002089040745945069943445560
表H4 <- study3_all_party_match_results$trends %>%
  dplyr::filter(status == "estimated") %>%
  dplyr::transmute(
    支持政党 = support_party_valid,
    `1選択肢増加あたりの変化(pp)` = round(estimate * 100, 2),
    `95%CI下限` = round(conf.low * 100, 2),
    `95%CI上限` = round(conf.high * 100, 2),
    p値 = signif(p.value, 3)
  )
knitr::kable(表日本語(表H4), format = "html", row.names = FALSE)
支持政党 1選択肢増加あたりの変化(pp) 95%CI下限 95%CI上限 p値
自由民主党 4.20 1.37 7.03 0.00372
国民民主党 3.23 -2.26 8.73 0.25000

I. 3実験横断分析

補図I1:主要仮説の線形傾向

主要仮説 <- hypothesis_test_summary %>%
  dplyr::mutate(
    実験 = dplyr::recode(study_id, study1 = "実験1(2023年)", study2 = "実験2(2026年)", study3 = "実験3(2026年)"),
    指標 = dplyr::case_when(
      stringr::str_detect(statistic, "party") ~ "政党手がかり重要度",
      stringr::str_detect(statistic, "economic") ~ "経済手がかり重要度",
      TRUE ~ statistic
    ),
    予測方向 = dplyr::recode(expected_direction, positive = "正", negative = "負")
  )

主要仮説 <- 主要仮説 %>%
  dplyr::mutate(
    傾きpp = 100 * estimate,
    下限pp = 100 * conf_low,
    上限pp = 100 * conf_high,
    表示行 = paste0(hypothesis, ":", 指標),
    数値ラベル = sprintf("%.2f", 傾きpp)
  )

補図I1 <- ggplot2::ggplot(主要仮説, ggplot2::aes(x = 傾きpp, y = stats::reorder(表示行, 傾きpp))) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.45) +
  ggplot2::geom_errorbarh(ggplot2::aes(xmin = 下限pp, xmax = 上限pp), height = 0.12, linewidth = 0.55) +
  ggplot2::geom_label(ggplot2::aes(label = 数値ラベル), size = 3.1, label.size = 0, fill = "white") +
  ggplot2::labs(x = "選択肢が1つ増えるときの重要度の変化(pp)", y = NULL) +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
補図I1

表I1 <- 主要仮説 %>%
  dplyr::transmute(
    実験,
    仮説 = hypothesis,
    指標,
    予測方向,
    傾き = round(estimate, 4),
    `95%CI下限` = round(conf_low, 4),
    `95%CI上限` = round(conf_high, 4),
    p値 = signif(p_value_two_sided, 3),
    判定 = conclusion
  )
knitr::kable(表日本語(表I1), format = "html", row.names = FALSE)
実験 仮説 指標 予測方向 傾き 95%CI下限 95%CI上限 p値 判定
実験1(2023年) H1a(実験1) 政党手がかり重要度 -0.0013 -0.0057 0.0030 0.536 点推定が予測方向と一致しない
実験1(2023年) H1b(実験1) 経済手がかり重要度 -0.0023 -0.0058 0.0002 0.076 点推定は予測方向だが、95%信頼区間が0を含む
実験2(2026年) H1a(実験2) 政党手がかり重要度 -0.0015 -0.0062 0.0025 0.387 点推定が予測方向と一致しない
実験2(2026年) H1b(実験2) 経済手がかり重要度 -0.0078 -0.0113 -0.0046 0.001 予測方向で95%信頼区間が0を含まず、統計的に支持
実験3(2026年) H2a(実験3) 政党手がかり重要度 -0.0162 -0.0223 -0.0103 0.001 点推定が予測方向と一致しない
実験3(2026年) H2b(実験3) 経済手がかり重要度 -0.0074 -0.0106 -0.0045 0.001 予測方向で95%信頼区間が0を含まず、統計的に支持

補図I2:選択肢数調整済み重要度の線形傾向

調整済み傾向 <- choice_set_adjusted_slope_summary %>%
  dplyr::mutate(
    実験 = dplyr::recode(study_id, study1 = "実験1(2023年)", study2 = "実験2(2026年)", study3 = "実験3(2026年)"),
    指標 = dplyr::case_when(
      stringr::str_detect(statistic, "party") ~ "政党手がかり重要度(選択肢数調整済み)",
      stringr::str_detect(statistic, "economic") ~ "経済手がかり重要度(選択肢数調整済み)",
      TRUE ~ statistic
    )
  )

調整済み傾向 <- 調整済み傾向 %>%
  dplyr::mutate(
    傾き表示 = 100 * estimate,
    下限表示 = 100 * conf_low,
    上限表示 = 100 * conf_high,
    表示行 = paste0(実験, ":", 指標),
    数値ラベル = sprintf("%.2f", 傾き表示)
  )

補図I2 <- ggplot2::ggplot(調整済み傾向, ggplot2::aes(x = 傾き表示, y = stats::reorder(表示行, 傾き表示))) +
  ggplot2::geom_vline(xintercept = 0, linewidth = 0.45) +
  ggplot2::geom_errorbarh(ggplot2::aes(xmin = 下限表示, xmax = 上限表示), height = 0.12, linewidth = 0.55) +
  ggplot2::geom_label(ggplot2::aes(label = 数値ラベル), size = 3.1, label.size = 0, fill = "white") +
  ggplot2::labs(x = "選択肢が1つ増えるときの調整済み重要度の変化(%)", y = NULL) +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank())
補図I2

表I2 <- 調整済み傾向 %>%
  dplyr::transmute(
    実験,
    指標,
    傾き = round(estimate, 4),
    `95%CI下限` = round(conf_low, 4),
    `95%CI上限` = round(conf_high, 4),
    p値 = signif(p_value_two_sided, 3)
  )
knitr::kable(表日本語(表I2), format = "html", row.names = FALSE)
実験 指標 傾き 95%CI下限 95%CI上限 p値
実験1(2023年) 政党手がかり重要度(選択肢数調整済み) 0.0463 0.0319 0.0616 0.001
実験1(2023年) 経済手がかり重要度(選択肢数調整済み) 0.0347 0.0253 0.0440 0.001
実験2(2026年) 政党手がかり重要度(選択肢数調整済み) 0.0414 0.0289 0.0528 0.001
実験2(2026年) 経済手がかり重要度(選択肢数調整済み) 0.0148 0.0064 0.0239 0.001
実験3(2026年) 政党手がかり重要度(選択肢数調整済み) 0.0552 0.0394 0.0734 0.001
実験3(2026年) 経済手がかり重要度(選択肢数調整済み) 0.0132 0.0047 0.0216 0.002

補図I3:政党手がかり相対比重の3実験比較

横断相対比重 <- cross_study_relative_weight %>%
  dplyr::mutate(
    実験 = dplyr::recode(study_id, study1 = "実験1(2023年)", study2 = "実験2(2026年)", study3 = "実験3(2026年)"),
    相対比重 = 100 * estimate,
    下限 = 100 * conf_low,
    上限 = 100 * conf_high,
    数値ラベル = sprintf("%.1f%%", 相対比重)
  )

補図I3 <- ggplot2::ggplot(横断相対比重, ggplot2::aes(x = party_n, y = 相対比重, group = 実験, linetype = 実験)) +
  ggplot2::geom_hline(yintercept = 50, linetype = "dashed", linewidth = 0.4) +
  ggplot2::geom_line(linewidth = 0.75) +
  ggplot2::geom_errorbar(ggplot2::aes(ymin = 下限, ymax = 上限), width = 0.07, linewidth = 0.45) +
  ggplot2::geom_label(ggplot2::aes(label = 数値ラベル), size = 3.0, label.size = 0, fill = "white") +
  ggplot2::scale_x_continuous(breaks = 2:5, labels = paste0(2:5, "選択肢")) +
  ggplot2::labs(x = "選択肢数", y = "政党手がかり相対比重(%)", linetype = NULL) +
  ggplot2::theme_bw(base_size = 11) +
  ggplot2::theme(panel.grid.minor = ggplot2::element_blank(), legend.position = "top")
補図I3

表I3 <- 横断相対比重 %>%
  dplyr::transmute(
    実験,
    条件 = paste0(party_n, "選択肢条件"),
    `政党手がかり相対比重(%)` = round(相対比重, 1),
    `95%CI下限` = round(下限, 1),
    `95%CI上限` = round(上限, 1)
  )
knitr::kable(表日本語(表I3), format = "html", row.names = FALSE)
実験 条件 政党手がかり相対比重(%) 95%CI下限 95%CI上限
実験1(2023年) 2選択肢条件 53.1 44.8 59.6
実験1(2023年) 3選択肢条件 54.7 47.4 60.5
実験1(2023年) 4選択肢条件 54.3 48.5 59.5
実験1(2023年) 5選択肢条件 55.6 49.6 60.5
実験2(2026年) 2選択肢条件 48.3 39.9 55.7
実験2(2026年) 3選択肢条件 47.1 42.1 53.1
実験2(2026年) 4選択肢条件 52.8 47.5 57.7
実験2(2026年) 5選択肢条件 59.4 54.4 63.3
実験3(2026年) 2選択肢条件 73.2 68.2 77.4
実験3(2026年) 3選択肢条件 72.8 68.9 76.5
実験3(2026年) 4選択肢条件 74.6 71.0 78.2
実験3(2026年) 5選択肢条件 75.6 72.2 78.6
LS0tCnRpdGxlOiAi44Kq44Oz44Op44Kk44Oz5LiK44Gn44Gu6KOc6YG644Go5YaN54++44Kz44O844OJIgpzdWJ0aXRsZTogIuWkmuWFmuWItuOBr+e1jOa4iOaKleelqOOCkuW8seOCgeOCi+OBruOBi++8n++8muaUv+WFmuOBruaJi+OBjOOBi+OCiuOBqOe1jOa4iOOBruaJi+OBjOOBi+OCiuOCkuOCgeOBkOOCi+OCs+ODs+OCuOODp+OCpOODs+ODiOWun+mokyIKYXV0aG9yOiAiSGFuYWtvIE9obXVyYSIKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJVktJW0tJWQnKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKcGFyYW1zOgogIHN0dWR5MV9kYXRhOiAicGFydHludW0uY3N2IgogIHN0dWR5Ml9kYXRhOiAiY29uam9pbnRfc3R1ZHkyLmNzdiIKICBzdHVkeTNfZGF0YTogImNvbmpvaW50X1MzLmNzdiIKICBvdXRwdXRfcm9vdDogImNvbmpvaW50X3JlcGxpY2F0aW9uX3Jlc3VsdHMiCiAgcnVuX2FuYWx5c2lzOiB0cnVlCiAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9COiAyMDAwCiAgc3VwcG9ydF9ib290c3RyYXBfQjogNTAwCiAgcmVydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcDogZmFsc2UKICByZXJ1bl9zdXBwb3J0X2Jvb3RzdHJhcDogZmFsc2UKICBtaW5fc3VwcG9ydF90b3RhbF9uOiAxNTAKICBtaW5fc3VwcG9ydF9jZWxsX246IDQwCi0tLQoKPHN0eWxlPgpib2R5IHsKICBmb250LWZhbWlseTogIkhlbHZldGljYSBOZXVlIiwgQXJpYWwsICJZdSBHb3RoaWMiLCAiSGlyYWdpbm8gS2FrdSBHb3RoaWMgUHJvTiIsIHNhbnMtc2VyaWY7CiAgZm9udC1zaXplOiAxNnB4OwogIGxpbmUtaGVpZ2h0OiAxLjc1Owp9Ci5tYWluLWNvbnRhaW5lciB7IG1heC13aWR0aDogMTEyMHB4OyB9CmgxLCBoMiwgaDMsIGg0IHsgZm9udC13ZWlnaHQ6IDcwMDsgfQpoMiB7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkOGRlZTQ7CiAgcGFkZGluZy1ib3R0b206IDAuMjVlbTsKfQpwcmUsIGNvZGUgeyBmb250LXNpemU6IDAuOTBlbTsgfQp0YWJsZSB7IGZvbnQtc2l6ZTogMC45MGVtOyB9Ci50YWJsZS1zY3JvbGwgeyBvdmVyZmxvdy14OiBhdXRvOyBtYXJnaW4tYm90dG9tOiAxLjVlbTsgfQppbWcgeyBtYXgtd2lkdGg6IDEwMCU7IGhlaWdodDogYXV0bzsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB9Ci5jb2RlLWNvbnRyb2xzIHsgbWFyZ2luOiAwLjVlbSAwIDEuMmVtIDA7IH0KLmNvZGUtY29udHJvbHMgYnV0dG9uIHsgbWFyZ2luLXJpZ2h0OiAwLjVlbTsgcGFkZGluZzogMC4zNWVtIDAuOGVtOyB9Cjwvc3R5bGU+Cgo8c2NyaXB0Pgpkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIiwgZnVuY3Rpb24oKSB7CiAgY29uc3Qgc2hvd0J1dHRvbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJzaG93LWFsbC1jb2RlIik7CiAgY29uc3QgaGlkZUJ1dHRvbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJoaWRlLWFsbC1jb2RlIik7CiAgaWYgKHNob3dCdXR0b24pIHsKICAgIHNob3dCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLCBmdW5jdGlvbigpIHsKICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiZGl2LnNvdXJjZUNvZGUiKS5mb3JFYWNoKGZ1bmN0aW9uKGVsKSB7CiAgICAgICAgZWwuc3R5bGUuZGlzcGxheSA9ICJibG9jayI7CiAgICAgIH0pOwogICAgfSk7CiAgfQogIGlmIChoaWRlQnV0dG9uKSB7CiAgICBoaWRlQnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIiwgZnVuY3Rpb24oKSB7CiAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoImRpdi5zb3VyY2VDb2RlIikuZm9yRWFjaChmdW5jdGlvbihlbCkgewogICAgICAgIGVsLnN0eWxlLmRpc3BsYXkgPSAibm9uZSI7CiAgICAgIH0pOwogICAgfSk7CiAgfQp9KTsKPC9zY3JpcHQ+Cgo8ZGl2IGNsYXNzPSJjb2RlLWNvbnRyb2xzIj4KPGJ1dHRvbiBpZD0ic2hvdy1hbGwtY29kZSIgdHlwZT0iYnV0dG9uIj5TaG93IEFsbCBDb2RlPC9idXR0b24+CjxidXR0b24gaWQ9ImhpZGUtYWxsLWNvZGUiIHR5cGU9ImJ1dHRvbiI+SGlkZSBBbGwgQ29kZTwvYnV0dG9uPgo8L2Rpdj4KCgojIFJFQURNRe+8muWGjeePvuaWueazleOBqOODleOCoeOCpOODq+ani+aIkAoK44GT44Gu44Kq44Oz44Op44Kk44Oz6KOc6YG644Go5YaN54++44Kz44O844OJ44Gv44CB6KuW5paH44CM5aSa5YWa5Yi244Gv57WM5riI5oqV56Wo44KS5byx44KB44KL44Gu44GL77yf77ya5pS/5YWa44Gu5omL44GM44GL44KK44Go57WM5riI44Gu5omL44GM44GL44KK44KS44KB44GQ44KL44Kz44Oz44K444On44Kk44Oz44OI5a6f6aiT44CN44Gn5aCx5ZGK44GZ44KLM+OBpOOBruWun+mok+OBruWIhuaekOOBq+OBpOOBhOOBpuOAgeacrOaWh+Wbs+OAgeijnOmBuuWbs+ihqOOAgemgkeWBpeaAp+WIhuaekOOAgeeEoeS9nOeCuuWMluODu+ODkOODqeODs+OCueiouuaWreOAgeOBiuOCiOOBs+aUr+aMgeaUv+WFmuWIpeWIhuaekOe1kOaenOOCkuOBvuOBqOOCgeOAgeOBleOCieOBq+OBneOCjOOCieOCkuWGjeePvuOBmeOCi+OBn+OCgeOBruOCs+ODvOODieOCkuOBvuOBqOOCgeOBn+OCguOBruOBp+OBguOCi+OAguS7peS4i+OBruaJi+mghuOBp+OAgeWFpeWKm+ODh+ODvOOCv+OBruiqrei+vOOBv+OBi+OCieacgOe1gueahOOBquWbs+ihqOODu+iouuaWree1kOaenOOBruaVtOeQhuOBvuOBp+OCkuS4gOaLrOOBl+OBpuWun+ihjOOBp+OBjeOCi+OAggoKIyMgMS4g5YaN54++44Gr5b+F6KaB44Gq44OV44Kh44Kk44Or562JCgrmrKHjga4044OV44Kh44Kk44Or44KS5ZCM44GY5L2c5qWt44OH44Kj44Os44Kv44OI44Oq44Gr572u44GE44Gm44KC44KJ44GG44CC44OH44O844K/44OV44Kh44Kk44Or5ZCN44KE5L+d5a2Y5aC05omA44KS5aSJ5pu044GZ44KL5aC05ZCI44Gv44CB44GT44GuUm1k5YaS6aCt44GuIGBwYXJhbXNgIOOCkuWkieabtOOBl+OBpuOCguOCieOBiOOBsOOCiOOBhOOAggoKfCDjg5XjgqHjgqTjg6sgfCDlhoXlrrkgfAp8LS0tfC0tLXwKfCBgcGFydHludW0uY3N2YCB8IOWun+mokzHjga7lhaXlipvjg4fjg7zjgr8gfAp8IGBjb25qb2ludF9zdHVkeTIuY3N2YCB8IOWun+mokzLjga7lhaXlipvjg4fjg7zjgr8gfAp8IGBjb25qb2ludF9TMy5jc3ZgIHwg5a6f6aiTM+OBruWFpeWKm+ODh+ODvOOCvyB8CgojIyAyLiDlv4XopoHjgapS44OR44OD44Kx44O844K4CgrliIbmnpDjgrPjg7zjg4njgafkvb/nlKjjgZnjgovkuLvopoHjg5Hjg4PjgrHjg7zjgrjjga/ku6XkuIvjga7jgajjgYrjgorjgafjgYLjgovjgIIKCmBgYHtyIHJlYWRtZS1pbnN0YWxsLXBhY2thZ2VzLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKGMoCiAgImRwbHlyIiwgInRpZHlyIiwgInN0cmluZ3IiLCAicHVycnIiLCAicmVhZHIiLAogICJmaXhlc3QiLCAidGliYmxlIiwgImZvcmNhdHMiLCAiZ2dwbG90MiIsICJzY2FsZXMiLAogICJzdXJ2aXZhbCIsICJnZ3RleHQiLCAicGF0Y2h3b3JrIiwgInJtYXJrZG93biIsICJrbml0ciIKKSkKYGBgCgojIyAzLiDlkITnqK7jga7jg4fjg5Xjgqnjg6vjg4joqK3lrpoKCuWGkumgreOBriBgcGFyYW1zYCDjgafjgIHlhaXlipvjg5XjgqHjgqTjg6vjgIHlh7rlipvlhYjjgIHjg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5flm57mlbDjgpLlpInmm7Tlj6/og73jgafjgYLjgovjgILnj77lnKjjga7kuLvopoHjgarjg4fjg5Xjgqnjg6vjg4jlgKTjga/mrKHjga7jgajjgYrjgorjgafjgYLjgovjgIIKCnwg44OR44Op44Oh44O844K/IHwg44OH44OV44Kp44Or44OIIHwg5oSP5ZGzIHwKfC0tLXwtLS06fC0tLXwKfCBgb3V0cHV0X3Jvb3RgIHwgYGNvbmpvaW50X3JlcGxpY2F0aW9uX3Jlc3VsdHNgIHwg5YWo5Ye65Yqb44KS5L+d5a2Y44GZ44KL44Or44O844OI44OH44Kj44Os44Kv44OI44OqIHwKfCBgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CYCB8IDIwMDAgfCDkuLvopoHjgarph43opoHluqbjg7vnm7jlr77mr5Tph43jga7jg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5flj43lvqnmlbAgfAp8IGBzdXBwb3J0X2Jvb3RzdHJhcF9CYCB8IDUwMCB8IOaUr+aMgeaUv+WFmuWIpeWIhuaekOOBruODluODvOODiOOCueODiOODqeODg+ODl+WPjeW+qeaVsCB8CgoKCiMjIDQuIOWHuuWKm+ODleOCoeOCpOODqwoK5YiG5p6Q57WQ5p6c44Gv44OH44OV44Kp44Or44OI44GnIGBjb25qb2ludF9yZXBsaWNhdGlvbl9yZXN1bHRzL2Ag5YaF44Gr5L+d5a2Y44GV44KM44KL6Kit5a6a44Gr44Gq44Gj44Gm44GE44KL44CC5Li744Gq5qeL5oiQ44Gv5Lul5LiL44Gu6YCa44KK44CCCgotIGBtYWluX3RleHQvYO+8muacrOaWh+eUqOOBruWbs+OBqOihqAotIGBzdXBwbGVtZW50L2DvvJrlrp/pqJPliKXjgYrjgojjgbPlrp/pqJPmqKrmlq3jga7oo5zpgbrlm7PooajvvIhDU1bjgIFMYVRlWOOAgeWbs++8iQotIGBkaWFnbm9zdGljcy9g77ya5qiZ5pys44K544Kv44Oq44O844OL44Oz44Kw44CB5Ymy5LuY44OQ44Op44Oz44K544CB44OX44Ot44OV44Kj44O844Or54Sh5L2c54K65YyW44Gu6Ki65patCi0gYG1vZGVsX29iamVjdHMvYO+8muWGjeWIqeeUqOWPr+iDveOBquODouODh+ODq+ODu+WIhuaekOOCquODluOCuOOCp+OCr+ODiAotIGBsb2dzL2DvvJpgc2Vzc2lvbkluZm9gIOOBquOBqeOBruWGjeePvuaAp+aDheWgsQoK5ZCE5YiG5p6Q44Gu6YCU5Lit44Gu57WM6YGO5L2c5oiQ44GV44KM44KL5ZCE56iu44Kq44OW44K444Kn44Kv44OI44Gq44Gp44GvIGBfd29ya2luZy9gIOOBq+S/neWtmOOBleOCjOOAgeacgOe1guautemajuOBp+S4iuiomOOBruODh+OCo+ODrOOCr+ODiOODquOBq+aVtOeQhuOBmeOCi+OCiOOBhuOBq+ioreWumuOBl+OBn+OAglLjgYrjgojjgbPlkITjg5Hjg4PjgrHjg7zjgrjjga7lrp/ooYznkrDlooPjga/jgIHliIbmnpDlrozkuoblvozjgasgYHNlc3Npb25JbmZvYCDjgajjgZfjgabkv53lrZjjgZXjgozjgovoqK3lrprjgajjgarjgaPjgabjgYTjgovjgIIKCiMjIDUuIOOBk+OBruOCquODs+ODqeOCpOODs+ijnOmBuuOBqOWGjeePvuOCs+ODvOODieOBruiqreOBv+aWuQoKKipB56+AKirjga/mnKzmlofjg7voo5zpgbrjga7lm7PooajjgpLnlJ/miJDjgZnjgovlrp/ooYzjgrPjg7zjg4njgIEqKkLnr4AqKuS7pemZjeOBr+WIhuaekOaomeacrOOAgeaOqOWumumHj+OAgeeEoeS9nOeCuuWMluODu+ODkOODqeODs+OCueiouuaWreOAgeOBiuOCiOOBs+WQhOijnOi2s+e1kOaenOOCkuOAgeOCs+ODvOODieOBqOWvvuW/nOOBleOBm+OBpueiuuiqjeOBmeOCi+OBn+OCgeOBruOCu+OCr+OCt+ODp+ODs+OBp+OBguOCi+OAgueUu+mdouS4iumDqOOBriAqKlNob3cgQWxsIENvZGUgLyBIaWRlIEFsbCBDb2RlKiog44G+44Gf44Gv5Y+z5LiK44GuICoqQ29kZSoqIOODoeODi+ODpeODvOOBi+OCieOAgeOCs+ODvOODieWFqOS9k+OBruihqOekuuODu+mdnuihqOekuuOCkuWIh+OCiuabv+OBiOOCieOCjOOCi+OAggoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogIGNvbW1lbnQgPSAiIz4iLAogIG91dC53aWR0aCA9ICI5NiUiCikKCm9wdGlvbnMoCiAgY29uam9pbnQuc3R1ZHkxX2RhdGEgPSBwYXJhbXMkc3R1ZHkxX2RhdGEsCiAgY29uam9pbnQuc3R1ZHkyX2RhdGEgPSBwYXJhbXMkc3R1ZHkyX2RhdGEsCiAgY29uam9pbnQuc3R1ZHkzX2RhdGEgPSBwYXJhbXMkc3R1ZHkzX2RhdGEsCiAgY29uam9pbnQub3V0cHV0X3Jvb3QgPSBwYXJhbXMkb3V0cHV0X3Jvb3QsCiAgY29uam9pbnQucmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CID0gYXMuaW50ZWdlcihwYXJhbXMkcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CKSwKICBjb25qb2ludC5zdXBwb3J0X2Jvb3RzdHJhcF9CID0gYXMuaW50ZWdlcihwYXJhbXMkc3VwcG9ydF9ib290c3RyYXBfQiksCiAgY29uam9pbnQucmVydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCA9IGlzVFJVRShwYXJhbXMkcmVydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCksCiAgY29uam9pbnQucmVydW5fc3VwcG9ydF9ib290c3RyYXAgPSBpc1RSVUUocGFyYW1zJHJlcnVuX3N1cHBvcnRfYm9vdHN0cmFwKSwKICBjb25qb2ludC5taW5fc3VwcG9ydF90b3RhbF9uID0gYXMuaW50ZWdlcihwYXJhbXMkbWluX3N1cHBvcnRfdG90YWxfbiksCiAgY29uam9pbnQubWluX3N1cHBvcnRfY2VsbF9uID0gYXMuaW50ZWdlcihwYXJhbXMkbWluX3N1cHBvcnRfY2VsbF9uKQopCgpzdXBwX3Jvb3QgPC0gZmlsZS5wYXRoKHBhcmFtcyRvdXRwdXRfcm9vdCwgInN1cHBsZW1lbnQiKQpkaWFnX3Jvb3QgPC0gZmlsZS5wYXRoKHBhcmFtcyRvdXRwdXRfcm9vdCwgImRpYWdub3N0aWNzIikKY3Jvc3Nfcm9vdCA8LSBmaWxlLnBhdGgoc3VwcF9yb290LCAiY3Jvc3Nfc3R1ZHkiKQoKCnN0dWR5X2NzdiA8LSBmdW5jdGlvbihzdHVkeV9pZCwgZmlsZSkgewogIGZpbGUucGF0aChzdXBwX3Jvb3QsIHN0dWR5X2lkLCAidGFibGVzX2NzdiIsIGZpbGUpCn0Kc3R1ZHlfZmlnIDwtIGZ1bmN0aW9uKHN0dWR5X2lkLCBmaWxlKSB7CiAgZmlsZS5wYXRoKHN1cHBfcm9vdCwgc3R1ZHlfaWQsICJmaWd1cmVzIiwgZmlsZSkKfQpkaWFnX2ZpZyA8LSBmdW5jdGlvbihzdHVkeV9pZCwgdHlwZSwgZmlsZSkgewogIGZpbGUucGF0aChkaWFnX3Jvb3QsIHN0dWR5X2lkLCB0eXBlLCBmaWxlKQp9CmNyb3NzX2NzdiA8LSBmdW5jdGlvbihmaWxlKSB7CiAgZmlsZS5wYXRoKGNyb3NzX3Jvb3QsICJ0YWJsZXNfY3N2IiwgZmlsZSkKfQpjcm9zc19maWcgPC0gZnVuY3Rpb24oZmlsZSkgewogIGZpbGUucGF0aChjcm9zc19yb290LCAiZmlndXJlcyIsIGZpbGUpCn0KYGBgCgoKIyBBLiDlkITlm7Pooajjga7lho3nj77jgrPjg7zjg4kKCiMjIEEuMSDlhbHpgJrjgrPjg7zjg4kKCmBgYHtyIGExLWNvbW1vbi1jb2RlLCBldmFsPXBhcmFtcyRydW5fYW5hbHlzaXMsIHJlc3VsdHM9J2hpZGUnLCBmaWcuc2hvdz0naGlkZSd9CiMg5YWx6YCa44Kz44O844OJCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKdW5pZmllZF9vdXRwdXRfcm9vdCA8LSBnZXRPcHRpb24oCiAgImNvbmpvaW50Lm91dHB1dF9yb290IiwKICAiY29uam9pbnRfcmVwbGljYXRpb25fcmVzdWx0cyIKKQoKZGlyLmNyZWF0ZSgKICB1bmlmaWVkX291dHB1dF9yb290LAogIHNob3dXYXJuaW5ncyA9IEZBTFNFLAogIHJlY3Vyc2l2ZSA9IFRSVUUKKQoKdW5pZmllZF9jb25maWcgPC0gbGlzdCgKICBvdXRwdXRfcm9vdCA9IHVuaWZpZWRfb3V0cHV0X3Jvb3QsCgogIGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uID0gInY0X3NjcmVlbmluZ19hdXRvZGV0ZWN0IiwKCiAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CID0gYXMuaW50ZWdlcigKICAgIGdldE9wdGlvbigiY29uam9pbnQucmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CIiwgMjAwMEwpCiAgKSwKICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3NlZWQgPSBhcy5pbnRlZ2VyKAogICAgZ2V0T3B0aW9uKCJjb25qb2ludC5yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3NlZWQiLCAyMDI2MDczMEwpCiAgKSwKICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3Byb2dyZXNzX2V2ZXJ5ID0gYXMuaW50ZWdlcigKICAgIGdldE9wdGlvbigiY29uam9pbnQucmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9wcm9ncmVzc19ldmVyeSIsIDEwMEwpCiAgKSwKICByZXJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwID0gaXNUUlVFKAogICAgZ2V0T3B0aW9uKCJjb25qb2ludC5yZXJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwIiwgRkFMU0UpCiAgKSwKCiAgbWluX3N1cHBvcnRfdG90YWxfbiA9IGFzLmludGVnZXIoCiAgICBnZXRPcHRpb24oImNvbmpvaW50Lm1pbl9zdXBwb3J0X3RvdGFsX24iLCAxNTBMKQogICksCiAgbWluX3N1cHBvcnRfY2VsbF9uID0gYXMuaW50ZWdlcigKICAgIGdldE9wdGlvbigiY29uam9pbnQubWluX3N1cHBvcnRfY2VsbF9uIiwgNDBMKQogICksCiAgc3VwcG9ydF9ib290c3RyYXBfQiA9IGFzLmludGVnZXIoCiAgICBnZXRPcHRpb24oImNvbmpvaW50LnN1cHBvcnRfYm9vdHN0cmFwX0IiLCA1MDBMKQogICksCiAgc3VwcG9ydF9ib290c3RyYXBfc2VlZCA9IGFzLmludGVnZXIoCiAgICBnZXRPcHRpb24oImNvbmpvaW50LnN1cHBvcnRfYm9vdHN0cmFwX3NlZWQiLCAyMDI2MDgwNkwpCiAgKSwKICByZXJ1bl9zdXBwb3J0X2Jvb3RzdHJhcCA9IGlzVFJVRSgKICAgIGdldE9wdGlvbigiY29uam9pbnQucmVydW5fc3VwcG9ydF9ib290c3RyYXAiLCBGQUxTRSkKICApLAoKICBzdHVkeTEgPSBsaXN0KAogICAgZGF0YV9maWxlID0gZ2V0T3B0aW9uKCJjb25qb2ludC5zdHVkeTFfZGF0YSIsICJwYXJ0eW51bS5jc3YiKSwKICAgIG91dHB1dF9kaXIgPSBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfcm9vdCwgIl93b3JraW5nIiwgInN0dWR5MSIpCiAgKSwKICBzdHVkeTIgPSBsaXN0KAogICAgZGF0YV9maWxlID0gZ2V0T3B0aW9uKCJjb25qb2ludC5zdHVkeTJfZGF0YSIsICJjb25qb2ludF9zdHVkeTIuY3N2IiksCiAgICBvdXRwdXRfZGlyID0gZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X3Jvb3QsICJfd29ya2luZyIsICJzdHVkeTIiKQogICksCiAgc3R1ZHkzID0gbGlzdCgKICAgIGRhdGFfZmlsZSA9IGdldE9wdGlvbigiY29uam9pbnQuc3R1ZHkzX2RhdGEiLCAiY29uam9pbnRfUzMuY3N2IiksCiAgICBvdXRwdXRfZGlyID0gZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X3Jvb3QsICJfd29ya2luZyIsICJzdHVkeTMiKQogICkKKQoKY2F0KAogICJVbmlmaWVkIGNvbmpvaW50IHJlcGxpY2F0aW9uIHBpcGVsaW5lXG4iLAogICJPdXRwdXQgcm9vdDogIiwgdW5pZmllZF9jb25maWckb3V0cHV0X3Jvb3QsICJcbiIsCiAgIlN0dWR5IDEgZGF0YTogIiwgdW5pZmllZF9jb25maWckc3R1ZHkxJGRhdGFfZmlsZSwgIlxuIiwKICAiU3R1ZHkgMiBkYXRhOiAiLCB1bmlmaWVkX2NvbmZpZyRzdHVkeTIkZGF0YV9maWxlLCAiXG4iLAogICJTdHVkeSAzIGRhdGE6ICIsIHVuaWZpZWRfY29uZmlnJHN0dWR5MyRkYXRhX2ZpbGUsICJcbiIsCiAgc2VwID0gIiIKKQoKCmRldGVjdF9maW5hbF9jb25zZW50X2NvbHVtbiA8LSBmdW5jdGlvbigKICByYXcsCiAgcHJlZmVycmVkX2NhbmRpZGF0ZXMgPSBjKCJROC4xIiwgIlE5LjEiLCAiUTEwLjEiKSwKICBzdHVkeV9sYWJlbCA9ICJTdHVkeSIKKSB7CiAgaWYgKCFpcy5kYXRhLmZyYW1lKHJhdykgfHwgbmNvbChyYXcpID09IDBMKSB7CiAgICBzdG9wKCJDaGVjayBkYXRhIikKICB9CgogIHByZXZpZXdfbiA8LSBtaW4oMTJMLCBucm93KHJhdykpCgogIG5vcm1hbGl6ZV9wcmV2aWV3IDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0gYXMuY2hhcmFjdGVyKHgpCiAgICB4W2lzLm5hKHgpXSA8LSAiIgogICAgeCA8LSBnc3ViKCLjgIAiLCAiICIsIHgsIGZpeGVkID0gVFJVRSkKICAgIHggPC0gZ3N1YigiW1s6c3BhY2U6XV0rIiwgIiAiLCB4KQogICAgdHJpbXdzKHgpCiAgfQoKICBzY29yZV9vbmUgPC0gZnVuY3Rpb24oY29sdW1uX25hbWUpIHsKICAgIHByZXZpZXcgPC0gcGFzdGUoCiAgICAgIG5vcm1hbGl6ZV9wcmV2aWV3KHV0aWxzOjpoZWFkKHJhd1tbY29sdW1uX25hbWVdXSwgcHJldmlld19uKSksCiAgICAgIGNvbGxhcHNlID0gIiAiCiAgICApCgogICAgc2NvcmUgPC0gMEwKCiAgICBpZiAoZ3JlcGwoIuacgOe1guaEj+aAneeiuuiqjSIsIHByZXZpZXcsIGZpeGVkID0gVFJVRSkpIHsKICAgICAgc2NvcmUgPC0gc2NvcmUgKyA4TAogICAgfQogICAgaWYgKGdyZXBsKCLjgZPjgaHjgonjgYzoqr/mn7vjga7mnIDlvozjga7nlLvpnaIiLCBwcmV2aWV3LCBmaXhlZCA9IFRSVUUpIHx8CiAgICAgICAgZ3JlcGwoIuiqv+afu+OBruacgOW+jOOBrueUu+mdoiIsIHByZXZpZXcsIGZpeGVkID0gVFJVRSkpIHsKICAgICAgc2NvcmUgPC0gc2NvcmUgKyA2TAogICAgfQogICAgaWYgKGdyZXBsKCLlm57nrZTntZDmnpzjgpLpgIHkv6HjgZnjgosiLCBwcmV2aWV3LCBmaXhlZCA9IFRSVUUpKSB7CiAgICAgIHNjb3JlIDwtIHNjb3JlICsgOEwKICAgIH0KICAgIGlmIChncmVwbCgi5Zue562U57WQ5p6c44KS6YCB5L+h44GX44Gq44GEIiwgcHJldmlldywgZml4ZWQgPSBUUlVFKSB8fAogICAgICAgIGdyZXBsKCLlm57nrZTjgpLpgIHkv6HjgZfjgarjgYQiLCBwcmV2aWV3LCBmaXhlZCA9IFRSVUUpKSB7CiAgICAgIHNjb3JlIDwtIHNjb3JlICsgNUwKICAgIH0KICAgIGlmIChncmVwbCgi5pys6Kq/5p+744Gu5Li75peo44Gr5ZCM5oSPIiwgcHJldmlldywgZml4ZWQgPSBUUlVFKSB8fAogICAgICAgIGdyZXBsKCLmnKzoqr/mn7vjga7otqPml6jjgavlkIzmhI8iLCBwcmV2aWV3LCBmaXhlZCA9IFRSVUUpKSB7CiAgICAgIHNjb3JlIDwtIHNjb3JlICsgM0wKICAgIH0KICAgIGlmIChjb2x1bW5fbmFtZSAlaW4lIHByZWZlcnJlZF9jYW5kaWRhdGVzKSB7CiAgICAgIHNjb3JlIDwtIHNjb3JlICsgMUwKICAgIH0KCiAgICBzY29yZQogIH0KCiAgY2FuZGlkYXRlX3RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgICBjb2x1bW4gPSBuYW1lcyhyYXcpLAogICAgc2NvcmUgPSB2YXBwbHkobmFtZXMocmF3KSwgc2NvcmVfb25lLCBpbnRlZ2VyKDEpKSwKICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICkKCiAgY2FuZGlkYXRlX3RhYmxlIDwtIGNhbmRpZGF0ZV90YWJsZVtjYW5kaWRhdGVfdGFibGUkc2NvcmUgPiAwTCwgLCBkcm9wID0gRkFMU0VdCgogIGlmIChucm93KGNhbmRpZGF0ZV90YWJsZSkgPT0gMEwpIHsKICAgIGV4aXN0aW5nX3ByZWZlcnJlZCA8LSBwcmVmZXJyZWRfY2FuZGlkYXRlc1sKICAgICAgcHJlZmVycmVkX2NhbmRpZGF0ZXMgJWluJSBuYW1lcyhyYXcpCiAgICBdCgogICAgaWYgKGxlbmd0aChleGlzdGluZ19wcmVmZXJyZWQpID09IDFMKSB7CiAgICAgIG1lc3NhZ2UoIkZpbmFsIGNvbnNlbnQ6ICIsIGV4aXN0aW5nX3ByZWZlcnJlZFtbMV1dKQogICAgICByZXR1cm4oZXhpc3RpbmdfcHJlZmVycmVkW1sxXV0pCiAgICB9CgogICAgbGlrZWx5X3F1ZXN0aW9uX2NvbHVtbnMgPC0gbmFtZXMocmF3KVsKICAgICAgZ3JlcGwoIl5RWzAtOV0rKFxcLlswLTldKyk/KF9bMC05XSspPyQiLCBuYW1lcyhyYXcpKQogICAgXQoKICAgIHN0b3AoIkNoZWNrIGZpbmFsIGNvbnNlbnQiKQogIH0KCiAgbWF4X3Njb3JlIDwtIG1heChjYW5kaWRhdGVfdGFibGUkc2NvcmUpCiAgYmVzdCA8LSBjYW5kaWRhdGVfdGFibGUkY29sdW1uW2NhbmRpZGF0ZV90YWJsZSRzY29yZSA9PSBtYXhfc2NvcmVdCgogIGlmIChsZW5ndGgoYmVzdCkgPiAxTCkgewogICAgcHJlZmVycmVkX2Jlc3QgPC0gcHJlZmVycmVkX2NhbmRpZGF0ZXNbCiAgICAgIHByZWZlcnJlZF9jYW5kaWRhdGVzICVpbiUgYmVzdAogICAgXQoKICAgIGlmIChsZW5ndGgocHJlZmVycmVkX2Jlc3QpID49IDFMKSB7CiAgICAgIGJlc3QgPC0gcHJlZmVycmVkX2Jlc3RbWzFdXQogICAgfSBlbHNlIHsKICAgICAgc3RvcCgiQ2hlY2sgZmluYWwgY29uc2VudCIpCiAgICB9CiAgfQoKICBtZXNzYWdlKCJGaW5hbCBjb25zZW50OiAiLCBiZXN0W1sxXV0pCgoKICBiZXN0W1sxXV0KfQoKcXVhbHRyaWNzX3ByZXZpZXdfdGV4dCA8LSBmdW5jdGlvbihyYXcsIGNvbHVtbl9uYW1lLCBwcmV2aWV3X24gPSAxMkwpIHsKICBpZiAoIWNvbHVtbl9uYW1lICVpbiUgbmFtZXMocmF3KSkgewogICAgcmV0dXJuKCIiKQogIH0KCiAgeCA8LSBhcy5jaGFyYWN0ZXIodXRpbHM6OmhlYWQocmF3W1tjb2x1bW5fbmFtZV1dLCBtaW4ocHJldmlld19uLCBucm93KHJhdykpKSkKICB4W2lzLm5hKHgpXSA8LSAiIgogIHggPC0gZ3N1Yigi44CAIiwgIiAiLCB4LCBmaXhlZCA9IFRSVUUpCiAgeCA8LSBnc3ViKCJbWzpzcGFjZTpdXSsiLCAiICIsIHgpCiAgdHJpbXdzKHBhc3RlKHgsIGNvbGxhcHNlID0gIiAiKSkKfQoKZnVsbHdpZHRoX2RpZ2l0IDwtIGZ1bmN0aW9uKG4pIHsKICBzdWJzdHIoIu+8kO+8ke+8ku+8k++8lO+8le+8lu+8l++8mO+8mSIsIG4gKyAxTCwgbiArIDFMKQp9CgpxdWVzdGlvbl9vcmRlcl9rZXkgPC0gZnVuY3Rpb24oeCkgewogIG0gPC0gcmVnZXhlYygiXlEoWzAtOV0rKVxcLihbMC05XSspIiwgeCkKICBwYXJ0cyA8LSByZWdtYXRjaGVzKHgsIG0pCgogIHZhcHBseSgKICAgIHBhcnRzLAogICAgZnVuY3Rpb24oeikgewogICAgICBpZiAobGVuZ3RoKHopIDwgM0wpIHsKICAgICAgICByZXR1cm4oSW5mKQogICAgICB9CiAgICAgIGFzLm51bWVyaWMoeltbMl1dKSAqIDEwMDAgKyBhcy5udW1lcmljKHpbWzNdXSkKICAgIH0sCiAgICBudW1lcmljKDEpCiAgKQp9CgpkZXRlY3RfYXR0ZW50aW9uX2NoZWNrX2NvbHVtbiA8LSBmdW5jdGlvbigKICByYXcsCiAgcHJlZmVycmVkX2NhbmRpZGF0ZXMgPSBjKCJRMjUuMV8xMSIsICJRMjUuMV8xMCIpLAogIHN0dWR5X2xhYmVsID0gIlN0dWR5IgopIHsKICBtZXRhZGF0YSA8LSBkYXRhLmZyYW1lKAogICAgY29sdW1uID0gbmFtZXMocmF3KSwKICAgIHRleHQgPSB2YXBwbHkobmFtZXMocmF3KSwgZnVuY3Rpb24odikgcXVhbHRyaWNzX3ByZXZpZXdfdGV4dChyYXcsIHYpLCBjaGFyYWN0ZXIoMSkpLAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgKQoKICBzY29yZSA8LSBpbnRlZ2VyKG5yb3cobWV0YWRhdGEpKQogIHNjb3JlIDwtIHNjb3JlICsgaWZlbHNlKGdyZXBsKCLlv4XjgZoiLCBtZXRhZGF0YSR0ZXh0LCBmaXhlZCA9IFRSVUUpLCA4TCwgMEwpCiAgc2NvcmUgPC0gc2NvcmUgKyBpZmVsc2UoZ3JlcGwoIumBuOOCkyIsIG1ldGFkYXRhJHRleHQsIGZpeGVkID0gVFJVRSksIDVMLCAwTCkKICBzY29yZSA8LSBzY29yZSArIGlmZWxzZShncmVwbCgiM3zvvJMiLCBtZXRhZGF0YSR0ZXh0KSwgNEwsIDBMKQogIHNjb3JlIDwtIHNjb3JlICsgaWZlbHNlKG1ldGFkYXRhJGNvbHVtbiAlaW4lIHByZWZlcnJlZF9jYW5kaWRhdGVzLCAxTCwgMEwpCiAgbWV0YWRhdGEkc2NvcmUgPC0gc2NvcmUKCiAgY2FuZGlkYXRlcyA8LSBtZXRhZGF0YVsKICAgIGdyZXBsKCLlv4XjgZoiLCBtZXRhZGF0YSR0ZXh0LCBmaXhlZCA9IFRSVUUpICYKICAgICAgZ3JlcGwoIumBuOOCkyIsIG1ldGFkYXRhJHRleHQsIGZpeGVkID0gVFJVRSkgJgogICAgICBncmVwbCgiM3zvvJMiLCBtZXRhZGF0YSR0ZXh0KSwKICAgICwKICAgIGRyb3AgPSBGQUxTRQogIF0KCiAgaWYgKG5yb3coY2FuZGlkYXRlcykgPT0gMEwpIHsKICAgIHN0b3AoIkNoZWNrIGF0dGVudGlvbiBpdGVtIikKICB9CgogIGNhbmRpZGF0ZXMgPC0gY2FuZGlkYXRlc1tvcmRlcigtY2FuZGlkYXRlcyRzY29yZSksICwgZHJvcCA9IEZBTFNFXQogIGJlc3Rfc2NvcmUgPC0gY2FuZGlkYXRlcyRzY29yZVtbMV1dCiAgYmVzdCA8LSBjYW5kaWRhdGVzJGNvbHVtbltjYW5kaWRhdGVzJHNjb3JlID09IGJlc3Rfc2NvcmVdCgogIGlmIChsZW5ndGgoYmVzdCkgPiAxTCkgewogICAgcHJlZmVycmVkX2Jlc3QgPC0gcHJlZmVycmVkX2NhbmRpZGF0ZXNbcHJlZmVycmVkX2NhbmRpZGF0ZXMgJWluJSBiZXN0XQogICAgaWYgKGxlbmd0aChwcmVmZXJyZWRfYmVzdCkgPT0gMUwpIHsKICAgICAgYmVzdCA8LSBwcmVmZXJyZWRfYmVzdAogICAgfSBlbHNlIHsKICAgICAgc3RvcCgiQ2hlY2sgYXR0ZW50aW9uIGl0ZW0iKQogICAgfQogIH0KCiAgbWVzc2FnZSgiQXR0ZW50aW9uIGl0ZW06ICIsIGJlc3RbWzFdXSkKICBiZXN0W1sxXV0KfQoKcmVzcG9uc2VfY29kZV9udW1lcmljIDwtIGZ1bmN0aW9uKHgpIHsKICB4IDwtIGFzLmNoYXJhY3Rlcih4KQogIHhbaXMubmEoeCldIDwtICIiCiAgeCA8LSBnc3ViKCLjgIAiLCAiICIsIHgsIGZpeGVkID0gVFJVRSkKICB4IDwtIHRyaW13cyhnc3ViKCJbWzpzcGFjZTpdXSsiLCAiICIsIHgpKQoKICBleGFjdCA8LSBncmVwbCgiXlswLTldKyg/OlxcLjArKT8kIiwgeCwgcGVybCA9IFRSVUUpCiAgb3V0IDwtIHJlcChOQV9yZWFsXywgbGVuZ3RoKHgpKQogIG91dFtleGFjdF0gPC0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKHhbZXhhY3RdKSkKCiAgdHJhaWxpbmcgPC0gcmVnZXhlYygiXFwoKFswLTldKylcXClcXHMqJCIsIHgpCiAgdHJhaWxpbmdfcGFydHMgPC0gcmVnbWF0Y2hlcyh4LCB0cmFpbGluZykKICB0cmFpbGluZ19jb2RlIDwtIHZhcHBseSgKICAgIHRyYWlsaW5nX3BhcnRzLAogICAgZnVuY3Rpb24oeikgaWYgKGxlbmd0aCh6KSA+PSAyTCkgYXMubnVtZXJpYyh6W1syXV0pIGVsc2UgTkFfcmVhbF8sCiAgICBudW1lcmljKDEpCiAgKQogIG91dFtpcy5uYShvdXQpICYgIWlzLm5hKHRyYWlsaW5nX2NvZGUpXSA8LSB0cmFpbGluZ19jb2RlW2lzLm5hKG91dCkgJiAhaXMubmEodHJhaWxpbmdfY29kZSldCgogIGZpcnN0X251bSA8LSBzdXBwcmVzc1dhcm5pbmdzKHJlYWRyOjpwYXJzZV9udW1iZXIoeCkpCiAgb3V0W2lzLm5hKG91dCldIDwtIGZpcnN0X251bVtpcy5uYShvdXQpXQogIG91dAp9CgpkZXRlY3RfYXR0ZW50aW9uX2NvcnJlY3RfY29kZSA8LSBmdW5jdGlvbigKICB4LAogIGRpc3BsYXllZF9hbnN3ZXIgPSAzTCwKICByZWNvZGVkX2Fuc3dlciA9IDZMLAogIHN0dWR5X2xhYmVsID0gIlN0dWR5IgopIHsKICBjb2RlIDwtIHJlc3BvbnNlX2NvZGVfbnVtZXJpYyh4KQogIHRhYiA8LSBzb3J0KHRhYmxlKGNvZGUsIHVzZU5BID0gIm5vIiksIGRlY3JlYXNpbmcgPSBUUlVFKQoKICBuX2Rpc3BsYXkgPC0gc3VtKGNvZGUgPT0gZGlzcGxheWVkX2Fuc3dlciwgbmEucm0gPSBUUlVFKQogIG5fcmVjb2RlIDwtIHN1bShjb2RlID09IHJlY29kZWRfYW5zd2VyLCBuYS5ybSA9IFRSVUUpCgogIGNob3NlbiA8LSBpZiAobl9yZWNvZGUgPiBuX2Rpc3BsYXkpIHJlY29kZWRfYW5zd2VyIGVsc2UgZGlzcGxheWVkX2Fuc3dlcgogIG5fbm9ubWlzc2luZyA8LSBzdW0oIWlzLm5hKGNvZGUpKQogIG5fY2hvc2VuIDwtIHN1bShjb2RlID09IGNob3NlbiwgbmEucm0gPSBUUlVFKQoKICBjYXQoIlxuIiwgc3R1ZHlfbGFiZWwsICLvvJrmjIfnpLrpoIXnm67jga7lm57nrZTjgrPjg7zjg4nliIbluINcbiIsIHNlcCA9ICIiKQogIHByaW50KHV0aWxzOjpoZWFkKHRhYiwgMTVMKSkKICBjYXQoCiAgICAi5o6h55So44GZ44KL5q2j562U44Kz44O844OJOiAiLCBjaG9zZW4sCiAgICAi77yI6KGo56S65LiK44Gu5q2j562U44GvM++8iVxuIiwKICAgIHNlcCA9ICIiCiAgKQoKICBpZiAobl9ub25taXNzaW5nID09IDBMIHx8IG5fY2hvc2VuIC8gbl9ub25taXNzaW5nIDwgMC41MCkgewogICAgc3RvcCgiQ2hlY2sgYXR0ZW50aW9uIGl0ZW0iKQogIH0KCiAgYXMuY2hhcmFjdGVyKGNob3NlbikKfQoKZGV0ZWN0X2NvbmpvaW50X2Nob2ljZV9tYXAgPC0gZnVuY3Rpb24oCiAgcmF3LAogIHBhcnR5X251bWJlcnMgPSAyOjUsCiAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkiCikgewogIG1ldGFkYXRhIDwtIGRhdGEuZnJhbWUoCiAgICBjb2x1bW4gPSBuYW1lcyhyYXcpLAogICAgdGV4dCA9IHZhcHBseShuYW1lcyhyYXcpLCBmdW5jdGlvbih2KSBxdWFsdHJpY3NfcHJldmlld190ZXh0KHJhdywgdiksIGNoYXJhY3RlcigxKSksCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICApCgogIG1hcHMgPC0gbGFwcGx5KAogICAgcGFydHlfbnVtYmVycywKICAgIGZ1bmN0aW9uKG5fcGFydHkpIHsKICAgICAgZGlnaXRfcGF0dGVybiA8LSBwYXN0ZTAoIig/OiIsIG5fcGFydHksICJ8IiwgZnVsbHdpZHRoX2RpZ2l0KG5fcGFydHkpLCAiKVxccyrjgaTjga7pgbjmip7ogqIiKQoKICAgICAgaGl0IDwtIGdyZXBsKCLku6XkuIvjgasiLCBtZXRhZGF0YSR0ZXh0LCBmaXhlZCA9IFRSVUUpICYKICAgICAgICBncmVwbCgi6YG45oqe6IKiIiwgbWV0YWRhdGEkdGV4dCwgZml4ZWQgPSBUUlVFKSAmCiAgICAgICAgZ3JlcGwoZGlnaXRfcGF0dGVybiwgbWV0YWRhdGEkdGV4dCwgcGVybCA9IFRSVUUpICYKICAgICAgICBncmVwbCgi6KGG6K2w6ZmiIiwgbWV0YWRhdGEkdGV4dCwgZml4ZWQgPSBUUlVFKSAmCiAgICAgICAgIWdyZXBsKCLmj5DnpLrjgZXjgozjgZ8uKumBuOaKnuiCouOBruaVsCIsIG1ldGFkYXRhJHRleHQsIHBlcmwgPSBUUlVFKSAmCiAgICAgICAgZ3JlcGwoIl5RWzAtOV0rXFwuWzAtOV0rJCIsIG1ldGFkYXRhJGNvbHVtbikKCiAgICAgIGNhbmRpZGF0ZXMgPC0gbWV0YWRhdGFbaGl0LCAsIGRyb3AgPSBGQUxTRV0KICAgICAgY2FuZGlkYXRlcyA8LSBjYW5kaWRhdGVzWwogICAgICAgIG9yZGVyKHF1ZXN0aW9uX29yZGVyX2tleShjYW5kaWRhdGVzJGNvbHVtbikpLAogICAgICAgICwKICAgICAgICBkcm9wID0gRkFMU0UKICAgICAgXQoKICAgICAgaWYgKG5yb3coY2FuZGlkYXRlcykgIT0gNUwpIHsKICAgICAgICBzdG9wKCJDaGVjayBjaG9pY2UgY29sdW1ucyIpCiAgICAgIH0KCiAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgcGFydHlfbiA9IG5fcGFydHksCiAgICAgICAgdGFzayA9IHNlcV9sZW4oNUwpLAogICAgICAgIGNob2ljZV92YXIgPSBjYW5kaWRhdGVzJGNvbHVtbiwKICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICAgICAgKQogICAgfQogICkKCiAgb3V0IDwtIGRwbHlyOjpiaW5kX3Jvd3MobWFwcykKICBtZXNzYWdlKCJDaG9pY2UgY29sdW1uczogT0siKQogIHByaW50KG91dCkKICBvdXQKfQoKZGV0ZWN0X21hbmlwdWxhdGlvbl9tYXAgPC0gZnVuY3Rpb24ocmF3LCBjaG9pY2VfbWFwLCBzdHVkeV9sYWJlbCA9ICJTdHVkeSIpIHsKICBtZXRhZGF0YV90ZXh0IDwtIHNldE5hbWVzKAogICAgdmFwcGx5KG5hbWVzKHJhdyksIGZ1bmN0aW9uKHYpIHF1YWx0cmljc19wcmV2aWV3X3RleHQocmF3LCB2KSwgY2hhcmFjdGVyKDEpKSwKICAgIG5hbWVzKHJhdykKICApCgogIG91dCA8LSBsYXBwbHkoCiAgICBzb3J0KHVuaXF1ZShjaG9pY2VfbWFwJHBhcnR5X24pKSwKICAgIGZ1bmN0aW9uKG5fcGFydHkpIHsKICAgICAgdmFycyA8LSBjaG9pY2VfbWFwJGNob2ljZV92YXJbY2hvaWNlX21hcCRwYXJ0eV9uID09IG5fcGFydHldCiAgICAgIHJvb3RzIDwtIHN1YigiXFwuWzAtOV0rJCIsICIiLCB2YXJzKQogICAgICByb290IDwtIG5hbWVzKHNvcnQodGFibGUocm9vdHMpLCBkZWNyZWFzaW5nID0gVFJVRSkpW1sxXV0KICAgICAgc3VmZml4IDwtIHN1cHByZXNzV2FybmluZ3MoYXMuaW50ZWdlcihzdWIoIl4uKlxcLiIsICIiLCB2YXJzKSkpCiAgICAgIGV4cGVjdGVkIDwtIHBhc3RlMChyb290LCAiLiIsIG1heChzdWZmaXgsIG5hLnJtID0gVFJVRSkgKyAxTCkKCiAgICAgIGNhbmRpZGF0ZXMgPC0gbmFtZXMobWV0YWRhdGFfdGV4dClbCiAgICAgICAgc3RhcnRzV2l0aChuYW1lcyhtZXRhZGF0YV90ZXh0KSwgcGFzdGUwKHJvb3QsICIuIikpICYKICAgICAgICAgIGdyZXBsKCLmj5DnpLrjgZXjgozjgZ8iLCBtZXRhZGF0YV90ZXh0LCBmaXhlZCA9IFRSVUUpICYKICAgICAgICAgIGdyZXBsKCLpgbjmip7ogqLjga7mlbAiLCBtZXRhZGF0YV90ZXh0LCBmaXhlZCA9IFRSVUUpCiAgICAgIF0KCiAgICAgIGlmIChleHBlY3RlZCAlaW4lIGNhbmRpZGF0ZXMpIHsKICAgICAgICBjaG9zZW4gPC0gZXhwZWN0ZWQKICAgICAgfSBlbHNlIGlmIChsZW5ndGgoY2FuZGlkYXRlcykgPT0gMUwpIHsKICAgICAgICBjaG9zZW4gPC0gY2FuZGlkYXRlc1tbMV1dCiAgICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiQ2hlY2sgbWFuaXB1bGF0aW9uIGl0ZW0iKQogICAgICB9CgogICAgICBkYXRhLmZyYW1lKAogICAgICAgIHBhcnR5X24gPSBuX3BhcnR5LAogICAgICAgIG1hbmlwdWxhdGlvbl92YXIgPSBjaG9zZW4sCiAgICAgICAgY29ycmVjdF9hbnN3ZXIgPSBhcy5jaGFyYWN0ZXIobl9wYXJ0eSksCiAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICkKICAgIH0KICApCgogIG91dCA8LSBkcGx5cjo6YmluZF9yb3dzKG91dCkKICBtZXNzYWdlKCJNYW5pcHVsYXRpb24gaXRlbTogT0siKQogIHByaW50KG91dCkKICBvdXQKfQoKcGFyc2VfY2hvaWNlX3Bvc2l0aW9uIDwtIGZ1bmN0aW9uKHgpIHsKICB4IDwtIGFzLmNoYXJhY3Rlcih4KQogIHhbaXMubmEoeCldIDwtICIiCiAgeCA8LSBnc3ViKCLjgIAiLCAiICIsIHgsIGZpeGVkID0gVFJVRSkKICB4IDwtIHRyaW13cyhnc3ViKCJbWzpzcGFjZTpdXSsiLCAiICIsIHgpKQoKICBsYWJlbF9tYXRjaCA8LSByZWdleGVjKCIoPzrmlL/lhZp854q25rOBfOmBuOaKnuiCoilcXHMqKFsxLTVdKSIsIHgsIHBlcmwgPSBUUlVFKQogIGxhYmVsX3BhcnRzIDwtIHJlZ21hdGNoZXMoeCwgbGFiZWxfbWF0Y2gpCiAgbGFiZWxfbnVtIDwtIHZhcHBseSgKICAgIGxhYmVsX3BhcnRzLAogICAgZnVuY3Rpb24oeikgaWYgKGxlbmd0aCh6KSA+PSAyTCkgYXMubnVtZXJpYyh6W1syXV0pIGVsc2UgTkFfcmVhbF8sCiAgICBudW1lcmljKDEpCiAgKQoKICBleGFjdCA8LSBncmVwbCgiXlsxLTVdKD86XFwuMCspPyQiLCB4LCBwZXJsID0gVFJVRSkKICBleGFjdF9udW0gPC0gcmVwKE5BX3JlYWxfLCBsZW5ndGgoeCkpCiAgZXhhY3RfbnVtW2V4YWN0XSA8LSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoeFtleGFjdF0pKQoKICB0cmFpbGluZyA8LSByZWdleGVjKCJcXCgoWzEtNV0pXFwpXFxzKiQiLCB4KQogIHRyYWlsaW5nX3BhcnRzIDwtIHJlZ21hdGNoZXMoeCwgdHJhaWxpbmcpCiAgdHJhaWxpbmdfbnVtIDwtIHZhcHBseSgKICAgIHRyYWlsaW5nX3BhcnRzLAogICAgZnVuY3Rpb24oeikgaWYgKGxlbmd0aCh6KSA+PSAyTCkgYXMubnVtZXJpYyh6W1syXV0pIGVsc2UgTkFfcmVhbF8sCiAgICBudW1lcmljKDEpCiAgKQoKICBvdXQgPC0gbGFiZWxfbnVtCiAgb3V0W2lzLm5hKG91dCldIDwtIGV4YWN0X251bVtpcy5uYShvdXQpXQogIG91dFtpcy5uYShvdXQpXSA8LSB0cmFpbGluZ19udW1baXMubmEob3V0KV0KICBvdXQKfQoKCmBgYAoKIyMgQS4yIOWun+mokzHvvJrmnKzmlofjga7lm7M044O75ZuzNQoKYGBge3IgYTItc3R1ZHkxLWNvZGUsIGV2YWw9cGFyYW1zJHJ1bl9hbmFseXNpcywgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30KIyDmnKzmlofjgrPjg7zjg4kKc3R1ZHkxX2VudiA8LSBsb2NhbCh7CnJlcXVpcmVkX3BhY2thZ2VzIDwtIGMoCiAgICAiZHBseXIiLAogICAgInRpZHlyIiwKICAgICJzdHJpbmdyIiwKICAgICJwdXJyciIsCiAgICAicmVhZHIiLAogICAgImZpeGVzdCIsCiAgICAidGliYmxlIiwKICAgICJmb3JjYXRzIiwKICAgICJnZ3Bsb3QyIiwKICAgICJzY2FsZXMiLAogICAgInN1cnZpdmFsIiwKICAgICJnZ3RleHQiLAogICAgInBhdGNod29yayIKICApCgogIG1pc3NpbmdfcGFja2FnZXMgPC0gcmVxdWlyZWRfcGFja2FnZXNbCiAgICAhdmFwcGx5KHJlcXVpcmVkX3BhY2thZ2VzLCByZXF1aXJlTmFtZXNwYWNlLCBsb2dpY2FsKDEpLCBxdWlldGx5ID0gVFJVRSkKICBdCgogIGlmIChsZW5ndGgobWlzc2luZ19wYWNrYWdlcykgPiAwKSB7CiAgICBzdG9wKCJObyBwYWNrYWdlcyIpCiAgfQoKICBsaWJyYXJ5KGRwbHlyKQogIGxpYnJhcnkodGlkeXIpCiAgbGlicmFyeShzdHJpbmdyKQogIGxpYnJhcnkocHVycnIpCiAgbGlicmFyeShyZWFkcikKICBsaWJyYXJ5KGZpeGVzdCkKICBsaWJyYXJ5KHRpYmJsZSkKICBsaWJyYXJ5KGZvcmNhdHMpCiAgbGlicmFyeShnZ3Bsb3QyKQogIGxpYnJhcnkoc2NhbGVzKQogIGxpYnJhcnkoc3Vydml2YWwpCiAgbGlicmFyeShwYXRjaHdvcmspCgogIGRhdGFfZmlsZSA8LSB1bmlmaWVkX2NvbmZpZyRzdHVkeTEkZGF0YV9maWxlCiAgb3V0cHV0X2RpciA8LSB1bmlmaWVkX2NvbmZpZyRzdHVkeTEkb3V0cHV0X2RpcgoKICBkaXIuY3JlYXRlKG91dHB1dF9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQoKICByZXF1aXJlX2luaXRpYWxfY29uc2VudCA8LSBUUlVFCiAgcmVxdWlyZV9maW5hbF9jb25zZW50IDwtIFRSVUUKICBpbml0aWFsX2NvbnNlbnRfdmFyIDwtICJRMS4xIgogIGZpbmFsX2NvbnNlbnRfdmFyIDwtICJROC4xIgoKICByZXF1aXJlX2F0dGVudGlvbl9jaGVjayA8LSBGQUxTRQogIHJlcXVpcmVfbWFuaXB1bGF0aW9uX2NoZWNrIDwtIEZBTFNFCiAgYXR0ZW50aW9uX2NoZWNrX3ZhciA8LSBOQV9jaGFyYWN0ZXJfCiAgYXR0ZW50aW9uX2NoZWNrX2NvcnJlY3QgPC0gTkFfY2hhcmFjdGVyXwoKICByZXF1aXJlX2FsbF9maXZlX3Rhc2tzIDwtIFRSVUUKCiAgdXNlX2VkdWNhdGlvbl9jb3ZhcmlhdGUgPC0gRkFMU0UKCiAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CIDwtIHVuaWZpZWRfY29uZmlnJHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQgogIHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfc2VlZCA8LSB1bmlmaWVkX2NvbmZpZyRyZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3NlZWQgKyAxTAogIHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfcHJvZ3Jlc3NfZXZlcnkgPC0gdW5pZmllZF9jb25maWckcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9wcm9ncmVzc19ldmVyeQoKICByZXJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwIDwtIHVuaWZpZWRfY29uZmlnJHJlcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAKCgogIG5vcm1fdGV4dCA8LSBmdW5jdGlvbih4KSB7CiAgICB4ICU+JQogICAgICBhcy5jaGFyYWN0ZXIoKSAlPiUKICAgICAgc3RyX3NxdWlzaCgpICU+JQogICAgICBzdHJfcmVwbGFjZV9hbGwoIu+9niIsICJ+IikgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgi44CcIiwgIn4iKQogIH0KCiAgYXNfbnVtIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHN1cHByZXNzV2FybmluZ3MocmVhZHI6OnBhcnNlX251bWJlcihub3JtX3RleHQoeCkpKQogIH0KCiAgaXNfcmVzcG9uc2VfY29kZSA8LSBmdW5jdGlvbih4LCBjb2RlKSB7CiAgICB4X25vcm0gPC0gbm9ybV90ZXh0KHgpCiAgICBjb2RlX2NociA8LSBhcy5jaGFyYWN0ZXIoY29kZSkKCiAgICB4X25vcm0gPT0gY29kZV9jaHIgfAogICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHhfbm9ybSwgcGFzdGUwKCJcXCgiLCBjb2RlX2NociwgIlxcKSQiKSkKICB9CgogIGZpcnN0X2V4aXN0aW5nIDwtIGZ1bmN0aW9uKGRhdCwgY2FuZGlkYXRlcykgewogICAgb3V0IDwtIGNhbmRpZGF0ZXNbY2FuZGlkYXRlcyAlaW4lIG5hbWVzKGRhdCldCiAgICBpZiAobGVuZ3RoKG91dCkgPT0gMCkgTkFfY2hhcmFjdGVyXyBlbHNlIG91dFsxXQogIH0KCiAgZ2V0X3ZhciA8LSBmdW5jdGlvbihkYXQsIGNhbmRpZGF0ZXMpIHsKICAgIHYgPC0gZmlyc3RfZXhpc3RpbmcoZGF0LCBjYW5kaWRhdGVzKQogICAgaWYgKGlzLm5hKHYpKSB7CiAgICAgIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KGRhdCkpCiAgICB9IGVsc2UgewogICAgICBkYXRbW3ZdXQogICAgfQogIH0KCiAgcmVsZXZlbF9pZl9wcmVzZW50IDwtIGZ1bmN0aW9uKHgsIHJlZikgewogICAgeCA8LSBmYWN0b3IoeCkKICAgIGlmIChyZWYgJWluJSBsZXZlbHMoeCkpIHsKICAgICAgcmVsZXZlbCh4LCByZWYgPSByZWYpCiAgICB9IGVsc2UgewogICAgICB4CiAgICB9CiAgfQoKICBmYWN0b3JfbWlzcyA8LSBmdW5jdGlvbih4LCBtaXNzID0gIuasoOaQjeODu+eEoeWbnuetlCIpIHsKICAgIHggPC0gbm9ybV90ZXh0KHgpCiAgICB4W2lzLm5hKHgpIHwgeCA9PSAiIiB8IHggPT0gIk5BIl0gPC0gbWlzcwogICAgZmFjdG9yKHgpCiAgfQoKICBtZWFuX2ltcHV0ZSA8LSBmdW5jdGlvbih4KSB7CiAgICB4IDwtIGFzLm51bWVyaWMoeCkKICAgIG1pc3MgPC0gYXMuaW50ZWdlcihpcy5uYSh4KSkKCiAgICBpZiAoYWxsKGlzLm5hKHgpKSkgewogICAgICB2YWx1ZSA8LSB4CiAgICB9IGVsc2UgewogICAgICB2YWx1ZSA8LSBpZmVsc2UoaXMubmEoeCksIG1lYW4oeCwgbmEucm0gPSBUUlVFKSwgeCkKICAgIH0KCiAgICBsaXN0KHZhbHVlID0gdmFsdWUsIG1pc3MgPSBtaXNzKQogIH0KCiAgd3JpdGVfY3N2X3NhZmVseSA8LSBmdW5jdGlvbih4LCBmaWxlbmFtZSkgewogICAgcmVhZHI6OndyaXRlX2Nzdih4LCBmaWxlLnBhdGgob3V0cHV0X2RpciwgZmlsZW5hbWUpLCBuYSA9ICIiKQogIH0KCiAgc2F2ZV9wbG90IDwtIGZ1bmN0aW9uKGZpbGVuYW1lLCBwbG90LCB3aWR0aCwgaGVpZ2h0LCBkcGkgPSAzMDApIHsKICAgIGdncGxvdDI6Omdnc2F2ZSgKICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgZmlsZW5hbWUpLAogICAgICBwbG90ID0gcGxvdCwKICAgICAgd2lkdGggPSB3aWR0aCwKICAgICAgaGVpZ2h0ID0gaGVpZ2h0LAogICAgICBkcGkgPSBkcGkKICAgICkKICB9CgoKICBpZiAoIWZpbGUuZXhpc3RzKGRhdGFfZmlsZSkpIHsKICAgIHN0b3AoIkNoZWNrIGRhdGEiKQogIH0KCiAgcmF3IDwtIHJlYWRyOjpyZWFkX2NzdigKICAgIGRhdGFfZmlsZSwKICAgIGNvbF90eXBlcyA9IGNvbHMoLmRlZmF1bHQgPSBjb2xfY2hhcmFjdGVyKCkpLAogICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSwKICAgIG5hbWVfcmVwYWlyID0gIm1pbmltYWwiCiAgKQoKICBpZiAoISJSZXNwb25zZUlkIiAlaW4lIG5hbWVzKHJhdykpIHsKICAgIHN0b3AoIkNoZWNrIGRhdGEiKQogIH0KCiAgbmFtZXMocmF3KSA8LSBuYW1lcyhyYXcpICU+JQogICAgc3RyX3JlcGxhY2UoIl5GXFwuKFxcZCspXFwuKFxcZCspXFwuKFxcZCspJCIsICJGLVxcMS1cXDItXFwzIikgJT4lCiAgICBzdHJfcmVwbGFjZSgiXkZcXC4oXFxkKylcXC4oXFxkKykkIiwgIkYtXFwxLVxcMiIpCgogIGlmICgKICAgIHJlcXVpcmVfZmluYWxfY29uc2VudCAmJgogICAgICAoCiAgICAgICAgaXMubmEoZmluYWxfY29uc2VudF92YXIpIHx8CiAgICAgICAgICAhZmluYWxfY29uc2VudF92YXIgJWluJSBuYW1lcyhyYXcpCiAgICAgICkKICApIHsKICAgIGNvbnNlbnRfcXVlc3Rpb25fcGF0dGVybiA8LSBwYXN0ZTAoCiAgICAgICLlm57nrZTntZDmnpzjgpLpgIHkv6HjgZnjgot8IiwKICAgICAgIuWbnuetlOOCkumAgeS/oeOBl+OBquOBhHwiLAogICAgICAi5Zue562U57WQ5p6c44KS6YCB5L+h44GX44Gq44GEfCIsCiAgICAgICLmnIDntYLmhI/mgJ3norroqo0iCiAgICApCgogICAgcHJldmlld19uIDwtIG1pbigxMEwsIG5yb3cocmF3KSkKCiAgICBkZXRlY3RlZF9maW5hbF9jb25zZW50X3ZhcnMgPC0gbmFtZXMocmF3KVsKICAgICAgdmFwcGx5KAogICAgICAgIHJhdywKICAgICAgICBmdW5jdGlvbihjb2x1bW4pIHsKICAgICAgICAgIHByZXZpZXcgPC0gbm9ybV90ZXh0KAogICAgICAgICAgICB1dGlsczo6aGVhZCgKICAgICAgICAgICAgICBjb2x1bW4sCiAgICAgICAgICAgICAgcHJldmlld19uCiAgICAgICAgICAgICkKICAgICAgICAgICkKCiAgICAgICAgICBhbnkoCiAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QoCiAgICAgICAgICAgICAgcHJldmlldywKICAgICAgICAgICAgICBjb25zZW50X3F1ZXN0aW9uX3BhdHRlcm4KICAgICAgICAgICAgKSwKICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICApCiAgICAgICAgfSwKICAgICAgICBsb2dpY2FsKDEpCiAgICAgICkKICAgIF0KCiAgICBpZiAobGVuZ3RoKGRldGVjdGVkX2ZpbmFsX2NvbnNlbnRfdmFycykgPT0gMUwpIHsKICAgICAgZmluYWxfY29uc2VudF92YXIgPC0gZGV0ZWN0ZWRfZmluYWxfY29uc2VudF92YXJzW1sxXV0KCiAgICAgIG1lc3NhZ2UoIkZpbmFsIGNvbnNlbnQ6ICIsIGZpbmFsX2NvbnNlbnRfdmFyKQogICAgfSBlbHNlIGlmIChsZW5ndGgoZGV0ZWN0ZWRfZmluYWxfY29uc2VudF92YXJzKSA+IDFMKSB7CiAgICAgIHN0b3AoIkNoZWNrIGZpbmFsIGNvbnNlbnQiKQogICAgfSBlbHNlIHsKICAgICAgbGlrZWx5X3F1ZXN0aW9uX2NvbHVtbnMgPC0gbmFtZXMocmF3KVsKICAgICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KAogICAgICAgICAgbmFtZXMocmF3KSwKICAgICAgICAgICJeUVswLTldKyg/OlxcLlswLTldKyk/JCIKICAgICAgICApCiAgICAgIF0KCiAgICAgIHN0b3AoIkNoZWNrIGZpbmFsIGNvbnNlbnQiKQogICAgfQogIH0KCiAgZGZfaGVhZGVyX3JlbW92ZWQgPC0gcmF3ICU+JQogICAgZmlsdGVyKAogICAgICAhaXMubmEoUmVzcG9uc2VJZCksCiAgICAgIFJlc3BvbnNlSWQgIT0gIiIsCiAgICAgICFzdHJfZGV0ZWN0KAogICAgICAgIG5vcm1fdGV4dChSZXNwb25zZUlkKSwKICAgICAgICAiXihSZXNwb25zZSBJRHzlm57nrZRJRCkkfEltcG9ydElkIgogICAgICApCiAgICApICU+JQogICAgbXV0YXRlKElEID0gYXMuY2hhcmFjdGVyKFJlc3BvbnNlSWQpKQoKICBkdXBsaWNhdGVfaWRzIDwtIGRmX2hlYWRlcl9yZW1vdmVkICU+JQogICAgY291bnQoSUQpICU+JQogICAgZmlsdGVyKG4gPiAxKQoKICBpZiAobnJvdyhkdXBsaWNhdGVfaWRzKSA+IDApIHsKICAgIHByaW50KGR1cGxpY2F0ZV9pZHMpCiAgICBzdG9wKCJDaGVjayIpCiAgfQoKICBzYW1wbGVfZmxvdyA8LSB0aWJibGUoCiAgICBzdGFnZSA9ICJRdWFsdHJpY3Pos6rllY/mlofooYzjg7tJbXBvcnRJZOihjOOCkumZpOWkluW+jCIsCiAgICBuID0gbnJvdyhkZl9oZWFkZXJfcmVtb3ZlZCkKICApCgogIGRmIDwtIGRmX2hlYWRlcl9yZW1vdmVkCgogIGlmIChyZXF1aXJlX2luaXRpYWxfY29uc2VudCkgewogICAgaWYgKGlzLm5hKGluaXRpYWxfY29uc2VudF92YXIpIHx8ICFpbml0aWFsX2NvbnNlbnRfdmFyICVpbiUgbmFtZXMoZGYpKSB7CiAgICAgIHN0b3AoIkNoZWNrIGluaXRpYWwgY29uc2VudCIpCiAgICB9CiAgICBkZiA8LSBkZiAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIGlzX3Jlc3BvbnNlX2NvZGUoLmRhdGFbW2luaXRpYWxfY29uc2VudF92YXJdXSwgMSkgfAogICAgICAgICAgc3RyX2RldGVjdCgKICAgICAgICAgICAgbm9ybV90ZXh0KC5kYXRhW1tpbml0aWFsX2NvbnNlbnRfdmFyXV0pLAogICAgICAgICAgICAi6Laj5peo44Gr5ZCM5oSP44GX44GmLirljZTlipvjgZnjgosiCiAgICAgICAgICApCiAgICAgICkKICAgIHNhbXBsZV9mbG93IDwtIGJpbmRfcm93cygKICAgICAgc2FtcGxlX2Zsb3csCiAgICAgIHRpYmJsZShzdGFnZSA9ICLliJ3lm57lkIzmhI/lm57nrZTjgpLkv53mjIEiLCBuID0gbnJvdyhkZikpCiAgICApCiAgfQoKICBpZiAocmVxdWlyZV9maW5hbF9jb25zZW50KSB7CiAgICBpZiAoaXMubmEoZmluYWxfY29uc2VudF92YXIpIHx8ICFmaW5hbF9jb25zZW50X3ZhciAlaW4lIG5hbWVzKGRmKSkgewogICAgICBzdG9wKCJDaGVjayBmaW5hbCBjb25zZW50IikKICAgIH0KICAgIGRmIDwtIGRmICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgaXNfcmVzcG9uc2VfY29kZSguZGF0YVtbZmluYWxfY29uc2VudF92YXJdXSwgMSkgfAogICAgICAgICAgc3RyX2RldGVjdCgKICAgICAgICAgICAgbm9ybV90ZXh0KC5kYXRhW1tmaW5hbF9jb25zZW50X3Zhcl1dKSwKICAgICAgICAgICAgIuWQjOaEj+OBly4q5Zue562U57WQ5p6c44KS6YCB5L+h44GZ44KLIgogICAgICAgICAgKQogICAgICApCiAgICBzYW1wbGVfZmxvdyA8LSBiaW5kX3Jvd3MoCiAgICAgIHNhbXBsZV9mbG93LAogICAgICB0aWJibGUoc3RhZ2UgPSAi5pyA57WC5ZCM5oSP5Zue562U44KS5L+d5oyBIiwgbiA9IG5yb3coZGYpKQogICAgKQogIH0KCiAgcHJpbnQoc2FtcGxlX2Zsb3cpCiAgd3JpdGVfY3N2X3NhZmVseShzYW1wbGVfZmxvdywgInNhbXBsZV9mbG93X2JlZm9yZV9jb25qb2ludC5jc3YiKQoKCiAgY2hvaWNlX21hcCA8LSB0cmliYmxlKAogICAgfnBhcnR5X24sIH50YXNrLCB+Y2hvaWNlX3ZhciwKICAgIDIsIDEsICJRMjQwIiwKICAgIDIsIDIsICJRMjUzIiwKICAgIDIsIDMsICJRMjU0IiwKICAgIDIsIDQsICJRMjU1IiwKICAgIDIsIDUsICJRMjU2IiwKCiAgICAzLCAxLCAiUTIzNSIsCiAgICAzLCAyLCAiUTI0MSIsCiAgICAzLCAzLCAiUTI0MiIsCiAgICAzLCA0LCAiUTI0MyIsCiAgICAzLCA1LCAiUTI0NCIsCgogICAgNCwgMSwgIlEyMzgiLAogICAgNCwgMiwgIlEyNDUiLAogICAgNCwgMywgIlEyNDYiLAogICAgNCwgNCwgIlEyNDciLAogICAgNCwgNSwgIlEyNDgiLAoKICAgIDUsIDEsICJRMjM5IiwKICAgIDUsIDIsICJRMjQ5IiwKICAgIDUsIDMsICJRMjUwIiwKICAgIDUsIDQsICJRMjUxIiwKICAgIDUsIDUsICJRMjUyIgogICkKCiAgaWYgKHJlcXVpcmVfbWFuaXB1bGF0aW9uX2NoZWNrKSB7CiAgICBzdG9wKCJDaGVjayIpCiAgfQoKCiAgbGV2ZWxfdG9fYXR0cl92YXIgPC0gZnVuY3Rpb24oeCkgewogICAgeCA8LSBub3JtX3RleHQoeCkKCiAgICBjYXNlX3doZW4oCiAgICAgIHggJWluJSBjKCLlj7PmtL7jg7vkv53lrojnmoQiLCAi5Lit6YGTIiwgIuW3pua0vuODu+mdqeaWsOeahCIpIH4KICAgICAgICAicG9saWN5X3Bvc2l0aW9uIiwKCiAgICAgIHggJWluJSBjKCLkuI7lhZoiLCAi6YeO5YWaIikgfgogICAgICAgICJnb3Zlcm5tZW50X3N0YXR1cyIsCgogICAgICBzdHJfZGV0ZWN0KHgsICJHRFDmiJDplbfnjociKSB+CiAgICAgICAgImdkcF9ncm93dGgiLAoKICAgICAgc3RyX2RldGVjdCh4LCAi5pel57WM5bmz5Z2HIikgfgogICAgICAgICJuaWtrZWkiLAoKICAgICAgeCAlaW4lIGMoIjEw5Lul5LiLIiwgIjEwfjQ5IiwgIjUwfjk5IiwgIjEwMH4xOTkiLCAiMjAw5Lul5LiKIikgfgogICAgICAgICJzZWF0cyIsCgogICAgICBzdHJfZGV0ZWN0KHgsICJDUEl854mp5L6hIikgfgogICAgICAgICJjcGkiLAoKICAgICAgc3RyX2RldGVjdCh4LCAi5aSx5qWt546HfOmbh+eUqCIpIH4KICAgICAgICAidW5lbXBsb3ltZW50IiwKCiAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfCiAgICApCiAgfQoKICByZXF1aXJlZF9hdHRyX3ZhcnMgPC0gYygKICAgICJwb2xpY3lfcG9zaXRpb24iLAogICAgImdvdmVybm1lbnRfc3RhdHVzIiwKICAgICJnZHBfZ3Jvd3RoIiwKICAgICJuaWtrZWkiLAogICAgInNlYXRzIiwKICAgICJjcGkiLAogICAgInVuZW1wbG95bWVudCIKICApCgogIGFsbG93ZWRfbGV2ZWxzIDwtIGxpc3QoCiAgICBwb2xpY3lfcG9zaXRpb24gPSBjKCLlj7PmtL7jg7vkv53lrojnmoQiLCAi5Lit6YGTIiwgIuW3pua0vuODu+mdqeaWsOeahCIpLAogICAgZ292ZXJubWVudF9zdGF0dXMgPSBjKCLkuI7lhZoiLCAi6YeO5YWaIiksCiAgICBnZHBfZ3Jvd3RoID0gYygKICAgICAgIkdEUOaIkOmVt+eOh8KxMO+8hSIsCiAgICAgICJHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICAgIkdEUOaIkOmVt+eOh+ODnuOCpOODiuOCuTHvvIUiCiAgICApLAogICAgbmlra2VpID0gYygKICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODl+ODqeOCuTEwMDDlhoYiLAogICAgICAi5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44Oe44Kk44OK44K5MTAwMOWGhiIsCiAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiCiAgICApLAogICAgc2VhdHMgPSBjKCIxMOS7peS4iyIsICIxMH40OSIsICI1MH45OSIsICIxMDB+MTk5IiwgIjIwMOS7peS4iiIpLAogICAgY3BpID0gYygKICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIsCiAgICAgICJDUEnliY3mnJ/mr5Tjg5fjg6njgrkx44Od44Kk44Oz44OIIiwKICAgICAgIkNQSeWJjeacn+avlOODnuOCpOODiuOCuTHjg53jgqTjg7Pjg4giCiAgICApLAogICAgdW5lbXBsb3ltZW50ID0gYygKICAgICAgIuWksealreeOh+WJjeacn+avlMKxMO+8hSIsCiAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg5fjg6njgrkx77yFIiwKICAgICAgIuWksealreeOh+WJjeacn+avlOODnuOCpOODiuOCuTHvvIUiCiAgICApCiAgKQoKCiAgbWFrZV9wcm9maWxlX2xvbmcgPC0gZnVuY3Rpb24oZGF0LCBuX3BhcnR5KSB7CgogICAgbWFwX24gPC0gY2hvaWNlX21hcCAlPiUKICAgICAgZmlsdGVyKHBhcnR5X24gPT0gbl9wYXJ0eSkKCiAgICBxdmFycyA8LSBtYXBfbiRjaG9pY2VfdmFyCgogICAgbWlzc2luZ19xIDwtIHNldGRpZmYocXZhcnMsIG5hbWVzKGRhdCkpCiAgICBpZiAobGVuZ3RoKG1pc3NpbmdfcSkgPiAwKSB7CiAgICAgIHN0b3AoIkNoZWNrIGNob2ljZSBjb2x1bW5zIikKICAgIH0KCiAgICBkYXRfbiA8LSBkYXQgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBpZl9hbnkoCiAgICAgICAgICBhbGxfb2YocXZhcnMpLAogICAgICAgICAgfiAhaXMubmEoLngpICYgbm9ybV90ZXh0KC54KSAhPSAiIgogICAgICAgICkKICAgICAgKQoKICAgIGNob2ljZV9sb25nIDwtIGRhdF9uICU+JQogICAgICBzZWxlY3QoSUQsIGFsbF9vZihxdmFycykpICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihxdmFycyksCiAgICAgICAgbmFtZXNfdG8gPSAiY2hvaWNlX3ZhciIsCiAgICAgICAgdmFsdWVzX3RvID0gImNob2ljZV9yYXciCiAgICAgICkgJT4lCiAgICAgIGxlZnRfam9pbihtYXBfbiwgYnkgPSAiY2hvaWNlX3ZhciIpICU+JQogICAgICBtdXRhdGUoY2hvaWNlID0gYXNfbnVtKGNob2ljZV9yYXcpKSAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShjaG9pY2UpKSAlPiUKICAgICAgc2VsZWN0KElELCBwYXJ0eV9uLCB0YXNrLCBjaG9pY2UpCgogICAgaW52YWxpZF9jaG9pY2UgPC0gY2hvaWNlX2xvbmcgJT4lCiAgICAgIGZpbHRlcihjaG9pY2UgPCAxIHwgY2hvaWNlID4gbl9wYXJ0eSkKCiAgICBpZiAobnJvdyhpbnZhbGlkX2Nob2ljZSkgPiAwKSB7CiAgICAgIHByaW50KGludmFsaWRfY2hvaWNlKQogICAgICBzdG9wKCJDaGVjayBjaG9pY2UgdmFsdWVzIikKICAgIH0KCiAgICBkdXBsaWNhdGVfY2hvaWNlIDwtIGNob2ljZV9sb25nICU+JQogICAgICBjb3VudChJRCwgdGFzaykgJT4lCiAgICAgIGZpbHRlcihuICE9IDEpCgogICAgaWYgKG5yb3coZHVwbGljYXRlX2Nob2ljZSkgPiAwKSB7CiAgICAgIHByaW50KGR1cGxpY2F0ZV9jaG9pY2UpCiAgICAgIHN0b3AoIkNoZWNrIGR1cGxpY2F0ZSBjaG9pY2VzIikKICAgIH0KCiAgICBsZXZlbF9yZWdleCA8LSAiXkYtKFsxLTVdKS0oWzEtNV0pLShbMS03XSkkIgogICAgbGV2ZWxfY29scyA8LSBuYW1lcyhkYXRfbilbc3RyX2RldGVjdChuYW1lcyhkYXRfbiksIGxldmVsX3JlZ2V4KV0KCiAgICBpZiAobGVuZ3RoKGxldmVsX2NvbHMpID09IDApIHsKICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICB9CgogICAgbGV2ZWxfbG9uZyA8LSBkYXRfbiAlPiUKICAgICAgc2VsZWN0KElELCBhbGxfb2YobGV2ZWxfY29scykpICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihsZXZlbF9jb2xzKSwKICAgICAgICBuYW1lc190byA9ICJmdmFyIiwKICAgICAgICB2YWx1ZXNfdG8gPSAibGV2ZWwiCiAgICAgICkgJT4lCiAgICAgIGV4dHJhY3QoCiAgICAgICAgZnZhciwKICAgICAgICBpbnRvID0gYygidGFzayIsICJwcm9maWxlIiwgImF0dHJfb3JkZXIiKSwKICAgICAgICByZWdleCA9IGxldmVsX3JlZ2V4LAogICAgICAgIGNvbnZlcnQgPSBUUlVFCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZShsZXZlbCA9IG5vcm1fdGV4dChsZXZlbCkpICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgdGFzayAlaW4lIDE6NSwKICAgICAgICBwcm9maWxlICVpbiUgMTpuX3BhcnR5LAogICAgICAgIGF0dHJfb3JkZXIgJWluJSAxOjcsCiAgICAgICAgIWlzLm5hKGxldmVsKSwKICAgICAgICBsZXZlbCAhPSAiIgogICAgICApICU+JQogICAgICBtdXRhdGUoYXR0cl92YXIgPSBsZXZlbF90b19hdHRyX3ZhcihsZXZlbCkpCgogICAgdW5rbm93bl9sZXZlbHMgPC0gbGV2ZWxfbG9uZyAlPiUKICAgICAgZmlsdGVyKGlzLm5hKGF0dHJfdmFyKSkgJT4lCiAgICAgIGRpc3RpbmN0KGxldmVsKQoKICAgIGlmIChucm93KHVua25vd25fbGV2ZWxzKSA+IDApIHsKICAgICAgcHJpbnQodW5rbm93bl9sZXZlbHMpCiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIHByb2ZpbGVfYXR0cmlidXRlX2NvdW50IDwtIGxldmVsX2xvbmcgJT4lCiAgICAgIGNvdW50KElELCB0YXNrLCBwcm9maWxlLCBuYW1lID0gIm5fYXR0cmlidXRlX3Jvd3MiKSAlPiUKICAgICAgZmlsdGVyKG5fYXR0cmlidXRlX3Jvd3MgIT0gNykKCiAgICBpZiAobnJvdyhwcm9maWxlX2F0dHJpYnV0ZV9jb3VudCkgPiAwKSB7CiAgICAgIHByaW50KGhlYWQocHJvZmlsZV9hdHRyaWJ1dGVfY291bnQsIDUwKSkKICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICB9CgogICAgZHVwbGljYXRlX2F0dHJpYnV0ZSA8LSBsZXZlbF9sb25nICU+JQogICAgICBjb3VudChJRCwgdGFzaywgcHJvZmlsZSwgYXR0cl92YXIpICU+JQogICAgICBmaWx0ZXIobiAhPSAxKQoKICAgIGlmIChucm93KGR1cGxpY2F0ZV9hdHRyaWJ1dGUpID4gMCkgewogICAgICBwcmludChoZWFkKGR1cGxpY2F0ZV9hdHRyaWJ1dGUsIDUwKSkKICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICB9CgogICAgcHJvZmlsZV93aWRlIDwtIGxldmVsX2xvbmcgJT4lCiAgICAgIGlubmVyX2pvaW4oY2hvaWNlX2xvbmcsIGJ5ID0gYygiSUQiLCAidGFzayIpKSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIHBhcnR5X24gPSBuX3BhcnR5LAogICAgICAgIHNlbGVjdGVkID0gYXMuaW50ZWdlcihwcm9maWxlID09IGNob2ljZSksCiAgICAgICAgdGFza19pZCA9IHBhc3RlKElELCBwYXJ0eV9uLCB0YXNrLCBzZXAgPSAiXyIpLAogICAgICAgIHByb2ZpbGVfaWQgPSBwYXN0ZShJRCwgcGFydHlfbiwgdGFzaywgcHJvZmlsZSwgc2VwID0gIl8iKQogICAgICApICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgSUQsIHBhcnR5X24sIHRhc2ssIHByb2ZpbGUsIGNob2ljZSwgc2VsZWN0ZWQsCiAgICAgICAgdGFza19pZCwgcHJvZmlsZV9pZCwgYXR0cl92YXIsIGxldmVsCiAgICAgICkgJT4lCiAgICAgIHBpdm90X3dpZGVyKAogICAgICAgIG5hbWVzX2Zyb20gPSBhdHRyX3ZhciwKICAgICAgICB2YWx1ZXNfZnJvbSA9IGxldmVsLAogICAgICAgIHZhbHVlc19mbiA9IGxpc3QobGV2ZWwgPSB+IGZpcnN0KC54KSkKICAgICAgKQoKICAgIG1pc3NpbmdfYXR0ciA8LSBzZXRkaWZmKHJlcXVpcmVkX2F0dHJfdmFycywgbmFtZXMocHJvZmlsZV93aWRlKSkKCiAgICBpZiAobGVuZ3RoKG1pc3NpbmdfYXR0cikgPiAwKSB7CiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIHByb2ZpbGVfd2lkZSAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELCBwYXJ0eV9uLCB0YXNrLCBwcm9maWxlLCBjaG9pY2UsIHNlbGVjdGVkLAogICAgICAgIHRhc2tfaWQsIHByb2ZpbGVfaWQsCiAgICAgICAgYWxsX29mKHJlcXVpcmVkX2F0dHJfdmFycykKICAgICAgKSAlPiUKICAgICAgYXJyYW5nZShJRCwgdGFzaywgcHJvZmlsZSkKICB9CgoKICBjb25qb2ludF8yIDwtIG1ha2VfcHJvZmlsZV9sb25nKGRmLCAyKQogIGNvbmpvaW50XzMgPC0gbWFrZV9wcm9maWxlX2xvbmcoZGYsIDMpCiAgY29uam9pbnRfNCA8LSBtYWtlX3Byb2ZpbGVfbG9uZyhkZiwgNCkKICBjb25qb2ludF81IDwtIG1ha2VfcHJvZmlsZV9sb25nKGRmLCA1KQoKICBjb25qb2ludF9hbGxfdW5maWx0ZXJlZCA8LSBiaW5kX3Jvd3MoCiAgICBjb25qb2ludF8yLAogICAgY29uam9pbnRfMywKICAgIGNvbmpvaW50XzQsCiAgICBjb25qb2ludF81CiAgKQoKCiAgaWRfdGFza19jaGVjayA8LSBjb25qb2ludF9hbGxfdW5maWx0ZXJlZCAlPiUKICAgIGdyb3VwX2J5KElELCBwYXJ0eV9uLCB0YXNrKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl9wcm9maWxlcyA9IG4oKSwKICAgICAgc2VsZWN0ZWRfc3VtID0gc3VtKHNlbGVjdGVkKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKSAlPiUKICAgIGdyb3VwX2J5KElELCBwYXJ0eV9uKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl90YXNrcyA9IG5fZGlzdGluY3QodGFzayksCiAgICAgIGFsbF90YXNrc19vayA9IGFsbChuX3Byb2ZpbGVzID09IHBhcnR5X24gJiBzZWxlY3RlZF9zdW0gPT0gMSksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkKCiAgaWYgKHJlcXVpcmVfYWxsX2ZpdmVfdGFza3MpIHsKICAgIHZhbGlkX2lkcyA8LSBpZF90YXNrX2NoZWNrICU+JQogICAgICBmaWx0ZXIobl90YXNrcyA9PSA1LCBhbGxfdGFza3Nfb2spCiAgfSBlbHNlIHsKICAgIHZhbGlkX2lkcyA8LSBpZF90YXNrX2NoZWNrICU+JQogICAgICBmaWx0ZXIoYWxsX3Rhc2tzX29rKQogIH0KCiAgY29uam9pbnRfYWxsIDwtIGNvbmpvaW50X2FsbF91bmZpbHRlcmVkICU+JQogICAgc2VtaV9qb2luKHZhbGlkX2lkcywgYnkgPSBjKCJJRCIsICJwYXJ0eV9uIikpCgogIG5fYnlfcGFydHkgPC0gdmFsaWRfaWRzICU+JQogICAgY291bnQocGFydHlfbiwgbmFtZSA9ICJuIikgJT4lCiAgICBjb21wbGV0ZShwYXJ0eV9uID0gMjo1LCBmaWxsID0gbGlzdChuID0gMCkpICU+JQogICAgYXJyYW5nZShwYXJ0eV9uKQoKICBuX3RvdGFsIDwtIHZhbGlkX2lkcyAlPiUKICAgIHN1bW1hcmlzZShuID0gbl9kaXN0aW5jdChJRCkpICU+JQogICAgcHVsbChuKQoKICBmaWd1cmVfbl9sYWJlbHMgPC0gYmluZF9yb3dzKAogICAgdGliYmxlKAogICAgICBwb3NpdGlvbiA9ICLlhajjgrXjg7Pjg5fjg6siLAogICAgICBsYWJlbCA9IHBhc3RlMCgi5YWo44K144Oz44OX44OrLCBuPSIsIHNjYWxlczo6Y29tbWEobl90b3RhbCkpCiAgICApLAogICAgbl9ieV9wYXJ0eSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIHBvc2l0aW9uID0gcGFzdGUwKHBhcnR5X24sICLmlL/lhZrpgbjmip4iKSwKICAgICAgICBsYWJlbCA9IHBhc3RlMCgibj0iLCBzY2FsZXM6OmNvbW1hKG4pKQogICAgICApICU+JQogICAgICBzZWxlY3QocG9zaXRpb24sIGxhYmVsKQogICkKCiAgc2FtcGxlX2Zsb3cgPC0gYmluZF9yb3dzKAogICAgc2FtcGxlX2Zsb3csCiAgICB0aWJibGUoCiAgICAgIHN0YWdlID0gIuWujOWFqOOBqjXoqrLpoYzjgpLjgoLjgaTliIbmnpDlr77osaHogIUiLAogICAgICBuID0gbl90b3RhbAogICAgKQogICkKCiAgY2F0KCJcbuWIhuaekOWvvuixoeiAheaVsFxuIikKICBwcmludChuX2J5X3BhcnR5KQogIGNhdCgi5YWo44K144Oz44OX44OrIG49Iiwgbl90b3RhbCwgIlxuIiwgc2VwID0gIiIpCgogIHdyaXRlX2Nzdl9zYWZlbHkoc2FtcGxlX2Zsb3csICJzYW1wbGVfZmxvdy5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkoaWRfdGFza19jaGVjaywgImlkX3Rhc2tfY2hlY2suY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KHZhbGlkX2lkcywgInZhbGlkX2lkcy5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkobl9ieV9wYXJ0eSwgIm5fYnlfcGFydHkuY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KGZpZ3VyZV9uX2xhYmVscywgImZpZ3VyZV9uX2xhYmVscy5jc3YiKQoKCiAgY2hlY2tfcHJvZmlsZSA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBncm91cF9ieShwYXJ0eV9uLCBJRCwgdGFzaywgdGFza19pZCkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG5fcHJvZmlsZXMgPSBuKCksCiAgICAgIHNlbGVjdGVkX3N1bSA9IHN1bShzZWxlY3RlZCksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkgJT4lCiAgICBjb3VudChwYXJ0eV9uLCBuX3Byb2ZpbGVzLCBzZWxlY3RlZF9zdW0pCgogIHByaW50KGNoZWNrX3Byb2ZpbGUpCiAgc3RvcGlmbm90KGFsbChjaGVja19wcm9maWxlJG5fcHJvZmlsZXMgPT0gY2hlY2tfcHJvZmlsZSRwYXJ0eV9uKSkKICBzdG9waWZub3QoYWxsKGNoZWNrX3Byb2ZpbGUkc2VsZWN0ZWRfc3VtID09IDEpKQoKICBhbGxvd2VkX2RmIDwtIGVuZnJhbWUoYWxsb3dlZF9sZXZlbHMsIG5hbWUgPSAibmFtZSIsIHZhbHVlID0gInZhbHVlIikgJT4lCiAgICB1bm5lc3QodmFsdWUpCgogIHVuZXhwZWN0ZWRfdmFsdWVzIDwtIGNvbmpvaW50X2FsbCAlPiUKICAgIHNlbGVjdChhbGxfb2YocmVxdWlyZWRfYXR0cl92YXJzKSkgJT4lCiAgICBwaXZvdF9sb25nZXIoCiAgICAgIGNvbHMgPSBldmVyeXRoaW5nKCksCiAgICAgIG5hbWVzX3RvID0gIm5hbWUiLAogICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiCiAgICApICU+JQogICAgZmlsdGVyKCFpcy5uYSh2YWx1ZSksIHZhbHVlICE9ICIiKSAlPiUKICAgIGRpc3RpbmN0KG5hbWUsIHZhbHVlKSAlPiUKICAgIGFudGlfam9pbihhbGxvd2VkX2RmLCBieSA9IGMoIm5hbWUiLCAidmFsdWUiKSkKCiAgcHJpbnQodW5leHBlY3RlZF92YWx1ZXMpCiAgc3RvcGlmbm90KG5yb3codW5leHBlY3RlZF92YWx1ZXMpID09IDApCgogIG9ic2VydmVkX2xldmVscyA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBzZWxlY3QoYWxsX29mKHJlcXVpcmVkX2F0dHJfdmFycykpICU+JQogICAgcGl2b3RfbG9uZ2VyKAogICAgICBjb2xzID0gZXZlcnl0aGluZygpLAogICAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLAogICAgICB2YWx1ZXNfdG8gPSAibGV2ZWwiCiAgICApICU+JQogICAgZGlzdGluY3QoYXR0cmlidXRlLCBsZXZlbCkgJT4lCiAgICBhcnJhbmdlKGF0dHJpYnV0ZSwgbGV2ZWwpCgogIHdyaXRlX2Nzdl9zYWZlbHkoY2hlY2tfcHJvZmlsZSwgInByb2ZpbGVfZXhwYW5zaW9uX2NoZWNrLmNzdiIpCiAgd3JpdGVfY3N2X3NhZmVseShvYnNlcnZlZF9sZXZlbHMsICJvYnNlcnZlZF9hdHRyaWJ1dGVfbGV2ZWxzLmNzdiIpCiAgd3JpdGVfY3N2X3NhZmVseShjb25qb2ludF9hbGwsICJzdHVkeTFfcHJvZmlsZV9sZXZlbF9kYXRhLmNzdiIpCgoKICBpZiAocmVxdWlyZV9hdHRlbnRpb25fY2hlY2spIHsKICAgIGlmICgKICAgICAgaXMubmEoYXR0ZW50aW9uX2NoZWNrX3ZhcikgfHwKICAgICAgICAhYXR0ZW50aW9uX2NoZWNrX3ZhciAlaW4lIG5hbWVzKGRmKSB8fAogICAgICAgIGlzLm5hKGF0dGVudGlvbl9jaGVja19jb3JyZWN0KQogICAgKSB7CiAgICAgIHN0b3AoIkNoZWNrIGF0dGVudGlvbiBpdGVtIikKICAgIH0KICB9CgogIGF0dGVudGlvbl9zdW1tYXJ5IDwtIHRpYmJsZSgKICAgIG5vdGUgPSAiMjAyM+W5tOWFg+OCs+ODvOODieOBp+OBr+azqOaEj+ODgeOCp+ODg+OCr+OBrueiuuWumuWvvuW/nOihqOOCkuS9v+eUqOOBl+OBpuOBhOOBquOBhOOBn+OCgeOAgeaomea6luWIhuaekOOBp+OBr+mbhuioiOOCkuecgeeVpeOAgiIKICApCgogIG1hbmlwdWxhdGlvbl9zdW1tYXJ5IDwtIHRpYmJsZSgKICAgIG5vdGUgPSAiMjAyM+W5tOWFg+OCs+ODvOODieOBp+OBr+aUv+WFmuaVsOeiuuiqjeizquWVj+OBrueiuuWumuWvvuW/nOihqOOCkuS9v+eUqOOBl+OBpuOBhOOBquOBhOOBn+OCgeOAgeaomea6luWIhuaekOOBp+OBr+mbhuioiOOCkuecgeeVpeOAgiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoYXR0ZW50aW9uX3N1bW1hcnksICJhdHRlbnRpb25fY2hlY2tfc3VtbWFyeS5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkobWFuaXB1bGF0aW9uX3N1bW1hcnksICJwYXJ0eV9udW1iZXJfY2hlY2tfc3VtbWFyeS5jc3YiKQoKCiAgY29uam9pbnRfYWxsX20gPC0gY29uam9pbnRfYWxsICU+JQogICAgbXV0YXRlKAogICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoc2VsZWN0ZWQpLAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCgogICAgICBwb2xpY3lfcG9zaXRpb24gPSBmYWN0b3IoCiAgICAgICAgcG9saWN5X3Bvc2l0aW9uLAogICAgICAgIGxldmVscyA9IGMoIuS4remBkyIsICLlj7PmtL7jg7vkv53lrojnmoQiLCAi5bem5rS+44O76Z2p5paw55qEIikKICAgICAgKSwKCiAgICAgIGdvdmVybm1lbnRfc3RhdHVzID0gZmFjdG9yKAogICAgICAgIGdvdmVybm1lbnRfc3RhdHVzLAogICAgICAgIGxldmVscyA9IGMoIumHjuWFmiIsICLkuI7lhZoiKQogICAgICApLAoKICAgICAgZ2RwX2dyb3d0aCA9IGZhY3RvcigKICAgICAgICBnZHBfZ3Jvd3RoLAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAiR0RQ5oiQ6ZW3546HwrEw77yFIiwKICAgICAgICAgICJHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICAgICAgICJHRFDmiJDplbfnjofjg57jgqTjg4rjgrkx77yFIgogICAgICAgICkKICAgICAgKSwKCiAgICAgIG5pa2tlaSA9IGZhY3RvcigKICAgICAgICBuaWtrZWksCiAgICAgICAgbGV2ZWxzID0gYygKICAgICAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiLAogICAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODl+ODqeOCuTEwMDDlhoYiLAogICAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODnuOCpOODiuOCuTEwMDDlhoYiCiAgICAgICAgKQogICAgICApLAoKICAgICAgc2VhdHMgPSBmYWN0b3IoCiAgICAgICAgc2VhdHMsCiAgICAgICAgbGV2ZWxzID0gYygiMTDku6XkuIsiLCAiMTB+NDkiLCAiNTB+OTkiLCAiMTAwfjE5OSIsICIyMDDku6XkuIoiKQogICAgICApLAoKICAgICAgY3BpID0gZmFjdG9yKAogICAgICAgIGNwaSwKICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIsCiAgICAgICAgICAiQ1BJ5YmN5pyf5q+U44OX44Op44K5MeODneOCpOODs+ODiCIsCiAgICAgICAgICAiQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIKICAgICAgICApCiAgICAgICksCgogICAgICB1bmVtcGxveW1lbnQgPSBmYWN0b3IoCiAgICAgICAgdW5lbXBsb3ltZW50LAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAi5aSx5qWt546H5YmN5pyf5q+UwrEw77yFIiwKICAgICAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg5fjg6njgrkx77yFIiwKICAgICAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg57jgqTjg4rjgrkx77yFIgogICAgICAgICkKICAgICAgKSwKCiAgICAgIHBhcnR5X25fZiA9IGZhY3RvcigKICAgICAgICBhcy5jaGFyYWN0ZXIocGFydHlfbiksCiAgICAgICAgbGV2ZWxzID0gYygiMiIsICIzIiwgIjQiLCAiNSIpCiAgICAgICkKICAgICkKCiAgYXR0cl90ZXJtcyA8LSBjKAogICAgInBvbGljeV9wb3NpdGlvbiIsCiAgICAiZ292ZXJubWVudF9zdGF0dXMiLAogICAgImdkcF9ncm93dGgiLAogICAgIm5pa2tlaSIsCiAgICAic2VhdHMiLAogICAgImNwaSIsCiAgICAidW5lbXBsb3ltZW50IgogICkKCgogIGZvcm11bGFfbm9jb3YgPC0gYXMuZm9ybXVsYSgKICAgIHBhc3RlKCJzZWxlY3RlZCB+IiwgcGFzdGUoYXR0cl90ZXJtcywgY29sbGFwc2UgPSAiICsgIikpCiAgKQoKICBydW5fYW1jZV9ub2NvdiA8LSBmdW5jdGlvbihkYXQpIHsKICAgIGZlb2xzKAogICAgICBmb3JtdWxhX25vY292LAogICAgICBkYXRhID0gZGF0LAogICAgICB2Y292ID0gfiBJRAogICAgKQogIH0KCiAgbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YgPC0gY29uam9pbnRfYWxsX20gJT4lCiAgICBzcGxpdCguJHBhcnR5X24pICU+JQogICAgbWFwKHJ1bl9hbWNlX25vY292KQoKICBjYXB0dXJlLm91dHB1dCgKICAgIGV0YWJsZShtb2RlbHNfYnlfcGFydHlfbl9ub2NvdiksCiAgICBmaWxlID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJhbWNlX25vY292X21vZGVscy50eHQiKQogICkKCgogIG1faW50ZXJhY3Rpb24gPC0gZmVvbHMoCiAgICBzZWxlY3RlZCB+CiAgICAgIHBhcnR5X25fZiAqCiAgICAgICgKICAgICAgICBwb2xpY3lfcG9zaXRpb24gKwogICAgICAgICAgZ292ZXJubWVudF9zdGF0dXMgKwogICAgICAgICAgZ2RwX2dyb3d0aCArCiAgICAgICAgICBuaWtrZWkgKwogICAgICAgICAgc2VhdHMgKwogICAgICAgICAgY3BpICsKICAgICAgICAgIHVuZW1wbG95bWVudAogICAgICApLAogICAgZGF0YSA9IGNvbmpvaW50X2FsbF9tLAogICAgdmNvdiA9IH4gSUQKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc3VtbWFyeShtX2ludGVyYWN0aW9uKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgImFtY2VfaW50ZXJhY3Rpb25fbW9kZWwudHh0IikKICApCgoKICB0aWR5X2ZpeGVzdCA8LSBmdW5jdGlvbihtb2RlbCkgewogICAgY3QgPC0gYXMuZGF0YS5mcmFtZShmaXhlc3Q6OmNvZWZ0YWJsZShtb2RlbCkpCiAgICBjdCR0ZXJtIDwtIHJvd25hbWVzKGN0KQoKICAgIGN0ICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgcmVuYW1lKAogICAgICAgIGVzdGltYXRlID0gRXN0aW1hdGUsCiAgICAgICAgc3RkLmVycm9yID0gYFN0ZC4gRXJyb3JgLAogICAgICAgIHN0YXRpc3RpYyA9IGB0IHZhbHVlYCwKICAgICAgICBwLnZhbHVlID0gYFByKD58dHwpYAogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgY29uZi5sb3cgPSBlc3RpbWF0ZSAtIDEuOTYgKiBzdGQuZXJyb3IsCiAgICAgICAgY29uZi5oaWdoID0gZXN0aW1hdGUgKyAxLjk2ICogc3RkLmVycm9yCiAgICAgICkgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICB0ZXJtLCBlc3RpbWF0ZSwgc3RkLmVycm9yLCBzdGF0aXN0aWMsIHAudmFsdWUsCiAgICAgICAgY29uZi5sb3csIGNvbmYuaGlnaAogICAgICApCiAgfQoKICB0ZXJtX2xhYmVscyA8LSB0cmliYmxlKAogICAgfnRlcm0sIH5hdHRyaWJ1dGUsIH5jdWVfdHlwZSwgfmxhYmVsLCB+b3JkZXIsCgogICAgImdvdmVybm1lbnRfc3RhdHVz5LiO5YWaIiwKICAgICLkuI7lhZrvvI/ph47lhZoiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuS4juWFmiIsIDEsCgogICAgInBvbGljeV9wb3NpdGlvbuWPs+a0vuODu+S/neWuiOeahCIsCiAgICAi5pS/562W5L2N572uIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLlj7PmtL7jg7vkv53lrojnmoQiLCAyLAoKICAgICJwb2xpY3lfcG9zaXRpb27lt6bmtL7jg7vpnanmlrDnmoQiLAogICAgIuaUv+etluS9jee9riIsICLmlL/lhZrjga7miYvjgYzjgYvjgooiLCAi5bem5rS+44O76Z2p5paw55qEIiwgMywKCiAgICAic2VhdHMxMH40OSIsCiAgICAi6K2w5bit5pWwIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLorbDluK3mlbDvvJoxMO+9njQ5IiwgNCwKCiAgICAic2VhdHM1MH45OSIsCiAgICAi6K2w5bit5pWwIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLorbDluK3mlbDvvJo1MO+9njk5IiwgNSwKCiAgICAic2VhdHMxMDB+MTk5IiwKICAgICLorbDluK3mlbAiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuitsOW4reaVsO+8mjEwMO+9njE5OSIsIDYsCgogICAgInNlYXRzMjAw5Lul5LiKIiwKICAgICLorbDluK3mlbAiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuitsOW4reaVsO+8mjIwMOS7peS4iiIsIDcsCgogICAgImdkcF9ncm93dGhHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICJHRFDmiJDplbfnjociLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIkdEUO+8muODl+ODqeOCuTHvvIUiLCA4LAoKICAgICJnZHBfZ3Jvd3RoR0RQ5oiQ6ZW3546H44Oe44Kk44OK44K5Me+8hSIsCiAgICAiR0RQ5oiQ6ZW3546HIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICJHRFDvvJrjg57jgqTjg4rjgrkx77yFIiwgOSwKCiAgICAibmlra2Vp5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44OX44Op44K5MTAwMOWGhiIsCiAgICAi5pel57WM5bmz5Z2HIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICLml6XntYzlubPlnYfvvJrjg5fjg6njgrkxMDAw5YaGIiwgMTAsCgogICAgIm5pa2tlaeaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODnuOCpOODiuOCuTEwMDDlhoYiLAogICAgIuaXpee1jOW5s+WdhyIsICLntYzmuIjjga7miYvjgYzjgYvjgooiLCAi5pel57WM5bmz5Z2H77ya44Oe44Kk44OK44K5MTAwMOWGhiIsIDExLAoKICAgICJjcGlDUEnliY3mnJ/mr5Tjg5fjg6njgrkx44Od44Kk44Oz44OIIiwKICAgICJDUEkiLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIkNQSe+8muODl+ODqeOCuTHjg53jgqTjg7Pjg4giLCAxMiwKCiAgICAiY3BpQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIsCiAgICAiQ1BJIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICJDUEnvvJrjg57jgqTjg4rjgrkx44Od44Kk44Oz44OIIiwgMTMsCgogICAgInVuZW1wbG95bWVudOWksealreeOh+WJjeacn+avlOODl+ODqeOCuTHvvIUiLAogICAgIuWksealreeOhyIsICLntYzmuIjjga7miYvjgYzjgYvjgooiLCAi5aSx5qWt546H77ya44OX44Op44K5Me+8hSIsIDE0LAoKICAgICJ1bmVtcGxveW1lbnTlpLHmpa3njofliY3mnJ/mr5Tjg57jgqTjg4rjgrkx77yFIiwKICAgICLlpLHmpa3njociLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIuWksealreeOh++8muODnuOCpOODiuOCuTHvvIUiLCAxNQogICkKCiAgYXR0cmlidXRlX29yZGVyIDwtIGMoCiAgICAi5LiO5YWa77yP6YeO5YWaIiwKICAgICLmlL/nrZbkvY3nva4iLAogICAgIuitsOW4reaVsCIsCiAgICAiR0RQ5oiQ6ZW3546HIiwKICAgICLml6XntYzlubPlnYciLAogICAgIkNQSSIsCiAgICAi5aSx5qWt546HIgogICkKCiAgbGFiZWxfb3JkZXIgPC0gdGVybV9sYWJlbHMgJT4lCiAgICBhcnJhbmdlKG9yZGVyKSAlPiUKICAgIHB1bGwobGFiZWwpCgogIG1ha2VfYW1jZV9wbG90X2RmIDwtIGZ1bmN0aW9uKG1vZGVscykgewogICAgaW1hcF9kZnIoCiAgICAgIG1vZGVscywKICAgICAgfiB0aWR5X2ZpeGVzdCgueCkgJT4lCiAgICAgICAgbXV0YXRlKHBhcnR5X24gPSBhcy5jaGFyYWN0ZXIoLnkpKQogICAgKSAlPiUKICAgICAgbGVmdF9qb2luKHRlcm1fbGFiZWxzLCBieSA9ICJ0ZXJtIikgJT4lCiAgICAgIGZpbHRlcighaXMubmEoYXR0cmlidXRlKSkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBlc3RpbWF0ZV9wcCA9IGVzdGltYXRlICogMTAwLAogICAgICAgIGNvbmYubG93X3BwID0gY29uZi5sb3cgKiAxMDAsCiAgICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICAgIHBhcnR5X24gPSBmYWN0b3IoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgbGV2ZWxzID0gYygiMiIsICIzIiwgIjQiLCAiNSIpLAogICAgICAgICAgbGFiZWxzID0gYygiMuaUv+WFmiIsICIz5pS/5YWaIiwgIjTmlL/lhZoiLCAiNeaUv+WFmiIpCiAgICAgICAgKSwKICAgICAgICBhdHRyaWJ1dGUgPSBmYWN0b3IoYXR0cmlidXRlLCBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIpLAogICAgICAgIGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSByZXYobGFiZWxfb3JkZXIpKQogICAgICApCiAgfQoKICBhbWNlX3Bsb3Rfbm9jb3YgPC0gbWFrZV9hbWNlX3Bsb3RfZGYobW9kZWxzX2J5X3BhcnR5X25fbm9jb3YpCiAgd3JpdGVfY3N2X3NhZmVseShhbWNlX3Bsb3Rfbm9jb3YsICJhbWNlX25vY292X2NvZWZmaWNpZW50cy5jc3YiKQoKICBpbnRlcmFjdGlvbl9wbG90X2RmIDwtIHRpZHlfZml4ZXN0KG1faW50ZXJhY3Rpb24pICU+JQogICAgZmlsdGVyKHN0cl9kZXRlY3QodGVybSwgInBhcnR5X25fZlszNDVdIikpICU+JQogICAgbXV0YXRlKAogICAgICBwYXJ0eV9uX2NvZGUgPSBzdHJfZXh0cmFjdCh0ZXJtLCAicGFydHlfbl9mWzM0NV0iKSwKICAgICAgcGFydHlfbiA9IHN0cl9yZW1vdmUocGFydHlfbl9jb2RlLCAicGFydHlfbl9mIiksCiAgICAgIGJhc2VfdGVybSA9IHRlcm0gJT4lCiAgICAgICAgc3RyX3JlbW92ZSgicGFydHlfbl9mWzM0NV06IikgJT4lCiAgICAgICAgc3RyX3JlbW92ZSgiOnBhcnR5X25fZlszNDVdIikKICAgICkgJT4lCiAgICBsZWZ0X2pvaW4odGVybV9sYWJlbHMsIGJ5ID0gYygiYmFzZV90ZXJtIiA9ICJ0ZXJtIikpICU+JQogICAgZmlsdGVyKCFpcy5uYShhdHRyaWJ1dGUpKSAlPiUKICAgIG11dGF0ZSgKICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICBwYXJ0eV9uX2xhYmVsID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gYygiMyIsICI0IiwgIjUiKSwKICAgICAgICBsYWJlbHMgPSBjKCIz5pS/5YWaIiwgIjTmlL/lhZoiLCAiNeaUv+WFmiIpCiAgICAgICksCiAgICAgIGF0dHJpYnV0ZSA9IGZhY3RvcihhdHRyaWJ1dGUsIGxldmVscyA9IGF0dHJpYnV0ZV9vcmRlciksCiAgICAgIGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSByZXYobGFiZWxfb3JkZXIpKQogICAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KGludGVyYWN0aW9uX3Bsb3RfZGYsICJhbWNlX2ludGVyYWN0aW9uX2NvZWZmaWNpZW50cy5jc3YiKQoKCiAgcmVjb2RlX2ZlbWFsZV9zdHVkeTEgPC0gZnVuY3Rpb24oeCkgewogICAgeF9jaHIgPC0gbm9ybV90ZXh0KHgpCiAgICB4X251bSA8LSBhc19udW0oeF9jaHIpCgogICAgY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KHhfY2hyLCAi5aWz5oCnIikgfCB4X251bSA9PSAxIH4gMUwsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLnlLfmgKciKSB8IHhfbnVtID09IDIgfiAwTCwKICAgICAgVFJVRSB+IE5BX2ludGVnZXJfCiAgICApCiAgfQoKICByZWNvZGVfY29sbGVnZV9ncmFkX3N0dWR5MSA8LSBmdW5jdGlvbih4KSB7CiAgICB4X2NociA8LSBub3JtX3RleHQoeCkKICAgIHhfbnVtIDwtIGFzX251bSh4X2NocikKCiAgICBjYXNlX3doZW4oCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICI05bm05Yi25aSn5a2mfO+8lOW5tOWItuWkp+WtpnzlpKflrabpmaIiKSB8CiAgICAgICAgeF9udW0gJWluJSBjKDQsIDUpIH4gMUwsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLlsI/lrabmoKF86auY5qChfOmrmOetieWwgumWgHznn63mnJ/lpKflraZ85bCC5L+u5a2m5qChIikgfAogICAgICAgIHhfbnVtICVpbiUgYygxLCAyLCAzKSB+IDBMLAogICAgICBUUlVFIH4gTkFfaW50ZWdlcl8KICAgICkKICB9CgogIHJlY29kZV9wYXJ0eV9zdXBwb3J0X3N0dWR5MSA8LSBmdW5jdGlvbih4KSB7CiAgICB4X2NociA8LSBub3JtX3RleHQoeCkKICAgIHhfbnVtIDwtIGFzX251bSh4X2NocikKCiAgICBjYXNlX3doZW4oCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLoh6rnlLHmsJHkuLt86Ieq5rCRIikgfCB4X251bSA9PSAxIH4gIuiHqueUseawkeS4u+WFmiIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLnq4vmhrLmsJHkuLsiKSB8IHhfbnVtID09IDIgfiAi56uL5oay5rCR5Li75YWaIiwKICAgICAgc3RyX2RldGVjdCh4X2NociwgIuWFrOaYjiIpIHwgeF9udW0gPT0gMyB+ICLlhazmmI7lhZoiLAogICAgICBzdHJfZGV0ZWN0KHhfY2hyLCAi57at5pawIikgfCB4X251bSA9PSA0IH4gIuaXpeacrOe2reaWsOOBruS8miIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLlhbHnlKMiKSB8IHhfbnVtID09IDUgfiAi5pel5pys5YWx55Sj5YWaIiwKICAgICAgc3RyX2RldGVjdCh4X2NociwgIuWbveawkeawkeS4uyIpIHwgeF9udW0gPT0gNiB+ICLlm73msJHmsJHkuLvlhZoiLAogICAgICBzdHJfZGV0ZWN0KHhfY2hyLCAi56S+5Lya5rCR5Li7fOekvuawkSIpIHwgeF9udW0gPT0gNyB+ICLnpL7kvJrmsJHkuLvlhZoiLAogICAgICBzdHJfZGV0ZWN0KHhfY2hyLCAi44KM44GE44KPIikgfCB4X251bSA9PSA4IH4gIuOCjOOBhOOCj+aWsOmBuOe1hCIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLjgZ3jga7ku5YiKSB8IHhfbnVtID09IDExIH4gIuOBneOBruS7liIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLmlK/mjIHjgZnjgovmlL/lhZrjga/jgarjgYR85pSv5oyB5pS/5YWa44Gq44GXIikgfAogICAgICAgIHhfbnVtID09IDEyIH4gIuaUr+aMgeaUv+WFmuOBquOBlyIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLjgo/jgYvjgonjgarjgYQiKSB8IHhfbnVtID09IDEzIH4gIuOCj+OBi+OCieOBquOBhCIsCiAgICAgIHN0cl9kZXRlY3QoeF9jaHIsICLnrZTjgYjjgarjgYR844GT44Gf44GI44Gq44GEIikgfCB4X251bSA9PSAxNCB+ICLnrZTjgYjjgarjgYQiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogIH0KCiAgZ2VuZGVyX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKCJRMi4xIiwgIlEyXzEiLCAiUTIuMS4iLCAi5oCn5YilIiwgImdlbmRlciIsICJHZW5kZXIiKQogICkKCiAgYWdlX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKCJRMi4yIiwgIlEyXzIiLCAiUTIuMi4iLCAi5bm06b2iIiwgImFnZSIsICJBZ2UiKQogICkKCiAgZWR1Y2F0aW9uX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKAogICAgICAiUTIuMyIsICJRMl8zIiwgIlEyLjMuIiwKICAgICAgIuWtpuattCIsICLmlZnogrLmrbQiLCAi5pyA57WC5a2m5q20IiwgImVkdWNhdGlvbiIsICJFZHVjYXRpb24iCiAgICApCiAgKQoKICBwYXJ0eV9zdXBwb3J0X3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKCJRMi40IiwgIlEyXzQiLCAiUTIuNC4iLCAi5pS/5YWa5pSv5oyBIiwgIuaUr+aMgeaUv+WFmiIsICJwYXJ0eV9zdXBwb3J0IikKICApCgogIGluY29tZV9ncm9zc19yYXcgPC0gZ2V0X3ZhcigKICAgIGRmLAogICAgYygiUTMuMV8xIiwgIlEzLjEuMSIsICJRM18xXzEiLCAi56iO5byV44GN5YmN5LiW5biv5bm05Y+OIiwgImluY29tZV9ncm9zcyIpCiAgKQoKICBpbmNvbWVfbmV0X3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKCJRMy4xXzIiLCAiUTMuMS4yIiwgIlEzXzFfMiIsICLmiYvlj5bjgorjga7lubTlj44iLCAiaW5jb21lX25ldCIpCiAgKQoKICBjb3Zhcl9pZCA8LSBkZiAlPiUKICAgIHRyYW5zbXV0ZSgKICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoUmVzcG9uc2VJZCksCiAgICAgIGZlbWFsZSA9IHJlY29kZV9mZW1hbGVfc3R1ZHkxKGdlbmRlcl9yYXcpLAogICAgICBhZ2VfcmF3X251bSA9IGFzX251bShhZ2VfcmF3KSwKICAgICAgY29sbGVnZV9ncmFkID0gcmVjb2RlX2NvbGxlZ2VfZ3JhZF9zdHVkeTEoZWR1Y2F0aW9uX3JhdyksCiAgICAgIHBhcnR5X3N1cHBvcnQgPSByZWNvZGVfcGFydHlfc3VwcG9ydF9zdHVkeTEocGFydHlfc3VwcG9ydF9yYXcpLAogICAgICBwYXJ0eV9zdXBwb3J0X2YgPSBmYWN0b3JfbWlzcyhwYXJ0eV9zdXBwb3J0KSwKICAgICAgaW5jb21lX2dyb3NzID0gYXNfbnVtKGluY29tZV9ncm9zc19yYXcpLAogICAgICBpbmNvbWVfbmV0ID0gYXNfbnVtKGluY29tZV9uZXRfcmF3KSwKICAgICAgaW5jb21lX2dyb3NzX2xvZyA9IGxvZzFwKGluY29tZV9ncm9zcyksCiAgICAgIGluY29tZV9uZXRfbG9nID0gbG9nMXAoaW5jb21lX25ldCkKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGFnZSA9IGNhc2Vfd2hlbigKICAgICAgICAhaXMubmEoYWdlX3Jhd19udW0pICYgYWdlX3Jhd19udW0gPj0gMTggJiBhZ2VfcmF3X251bSA8PSA4MCB+CiAgICAgICAgICBhZ2VfcmF3X251bSwKICAgICAgICAhaXMubmEoYWdlX3Jhd19udW0pICYgYWdlX3Jhd19udW0gPj0gMSAmIGFnZV9yYXdfbnVtIDw9IDYzIH4KICAgICAgICAgIGFnZV9yYXdfbnVtICsgMTcsCiAgICAgICAgVFJVRSB+IE5BX3JlYWxfCiAgICAgICkKICAgICkgJT4lCiAgICBzZW1pX2pvaW4odmFsaWRfaWRzICU+JSBzZWxlY3QoSUQpLCBieSA9ICJJRCIpICU+JQogICAgZGlzdGluY3QoSUQsIC5rZWVwX2FsbCA9IFRSVUUpCgogIGFnZV9pbXBfb2JqIDwtIG1lYW5faW1wdXRlKGNvdmFyX2lkJGFnZSkKICBpbmNvbWVfZ3Jvc3NfaW1wX29iaiA8LSBtZWFuX2ltcHV0ZShjb3Zhcl9pZCRpbmNvbWVfZ3Jvc3NfbG9nKQoKICBjb3Zhcl9pZCA8LSBjb3Zhcl9pZCAlPiUKICAgIG11dGF0ZSgKICAgICAgZmVtYWxlX2ltcCA9IGlmX2Vsc2UoaXMubmEoZmVtYWxlKSwgMEwsIGZlbWFsZSksCiAgICAgIGZlbWFsZV9taXNzID0gYXMuaW50ZWdlcihpcy5uYShmZW1hbGUpKSwKCiAgICAgIGNvbGxlZ2VfZ3JhZF9pbXAgPSBpZl9lbHNlKGlzLm5hKGNvbGxlZ2VfZ3JhZCksIDBMLCBjb2xsZWdlX2dyYWQpLAogICAgICBjb2xsZWdlX2dyYWRfbWlzcyA9IGFzLmludGVnZXIoaXMubmEoY29sbGVnZV9ncmFkKSksCgogICAgICBhZ2VfaW1wID0gYWdlX2ltcF9vYmokdmFsdWUsCiAgICAgIGFnZV9taXNzID0gYWdlX2ltcF9vYmokbWlzcywKCiAgICAgIGluY29tZV9ncm9zc19sb2dfaW1wID0gaW5jb21lX2dyb3NzX2ltcF9vYmokdmFsdWUsCiAgICAgIGluY29tZV9ncm9zc19sb2dfbWlzcyA9IGluY29tZV9ncm9zc19pbXBfb2JqJG1pc3MKICAgICkKCiAgY292YXJpYXRlX21pc3Npbmdfc3VtbWFyeSA8LSBjb3Zhcl9pZCAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl9pZHMgPSBuX2Rpc3RpbmN0KElEKSwKICAgICAgZmVtYWxlX21pc3NpbmcgPSBzdW0oaXMubmEoZmVtYWxlKSksCiAgICAgIGFnZV9taXNzaW5nID0gc3VtKGlzLm5hKGFnZSkpLAogICAgICBjb2xsZWdlX2dyYWRfbWlzc2luZyA9IHN1bShpcy5uYShjb2xsZWdlX2dyYWQpKSwKICAgICAgaW5jb21lX2dyb3NzX21pc3NpbmcgPSBzdW0oaXMubmEoaW5jb21lX2dyb3NzX2xvZykpLAogICAgICBwYXJ0eV9zdXBwb3J0X21pc3NpbmcgPSBzdW0oaXMubmEocGFydHlfc3VwcG9ydCkpCiAgICApCgogIHByaW50KGNvdmFyaWF0ZV9taXNzaW5nX3N1bW1hcnkpCiAgd3JpdGVfY3N2X3NhZmVseShjb3Zhcl9pZCwgInJlc3BvbmRlbnRfY292YXJpYXRlcy5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkoY292YXJpYXRlX21pc3Npbmdfc3VtbWFyeSwgImNvdmFyaWF0ZV9taXNzaW5nX3N1bW1hcnkuY3N2IikKCgogIGNvbmpvaW50X2FsbF9jb3YgPC0gY29uam9pbnRfYWxsX20gJT4lCiAgICBsZWZ0X2pvaW4oY292YXJfaWQsIGJ5ID0gIklEIikKCiAgY292YXJpYXRlX3Rlcm1zIDwtIGMoCiAgICAiZmVtYWxlX2ltcCIsCiAgICAiZmVtYWxlX21pc3MiLAogICAgImFnZV9pbXAiLAogICAgImFnZV9taXNzIiwKICAgICJpbmNvbWVfZ3Jvc3NfbG9nX2ltcCIsCiAgICAiaW5jb21lX2dyb3NzX2xvZ19taXNzIiwKICAgICJwYXJ0eV9zdXBwb3J0X2YiCiAgKQoKICBpZiAodXNlX2VkdWNhdGlvbl9jb3ZhcmlhdGUpIHsKICAgIGNvdmFyaWF0ZV90ZXJtcyA8LSBjKAogICAgICBjb3ZhcmlhdGVfdGVybXMsCiAgICAgICJjb2xsZWdlX2dyYWRfaW1wIiwKICAgICAgImNvbGxlZ2VfZ3JhZF9taXNzIgogICAgKQogIH0KCiAgaGFzX3ZhcmlhdGlvbiA8LSBmdW5jdGlvbihkYXQsIHYpIHsKICAgIGlmICghdiAlaW4lIG5hbWVzKGRhdCkpIHJldHVybihGQUxTRSkKICAgIGRwbHlyOjpuX2Rpc3RpbmN0KGRhdFtbdl1dLCBuYS5ybSA9IFRSVUUpID4gMQogIH0KCiAgY292YXJpYXRlX3Rlcm1zX3VzZSA8LSBjb3ZhcmlhdGVfdGVybXNbCiAgICBtYXBfbGdsKGNvdmFyaWF0ZV90ZXJtcywgfiBoYXNfdmFyaWF0aW9uKGNvbmpvaW50X2FsbF9jb3YsIC54KSkKICBdCgogIGZvcm11bGFfY292IDwtIGFzLmZvcm11bGEoCiAgICBwYXN0ZSgKICAgICAgInNlbGVjdGVkIH4iLAogICAgICBwYXN0ZShjKGF0dHJfdGVybXMsIGNvdmFyaWF0ZV90ZXJtc191c2UpLCBjb2xsYXBzZSA9ICIgKyAiKQogICAgKQogICkKCiAgcnVuX2FtY2VfY292IDwtIGZ1bmN0aW9uKGRhdCkgewogICAgZmVvbHMoCiAgICAgIGZvcm11bGFfY292LAogICAgICBkYXRhID0gZGF0LAogICAgICB2Y292ID0gfiBJRAogICAgKQogIH0KCiAgbW9kZWxzX2J5X3BhcnR5X25fY292IDwtIGNvbmpvaW50X2FsbF9jb3YgJT4lCiAgICBzcGxpdCguJHBhcnR5X24pICU+JQogICAgbWFwKHJ1bl9hbWNlX2NvdikKCiAgY2FwdHVyZS5vdXRwdXQoCiAgICBldGFibGUoCiAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX25vY292LAogICAgICBtb2RlbHNfYnlfcGFydHlfbl9jb3YsCiAgICAgIGhlYWRlcnMgPSBjKAogICAgICAgIHJlcCgi5YWx5aSJ6YeP44Gq44GXIiwgbGVuZ3RoKG1vZGVsc19ieV9wYXJ0eV9uX25vY292KSksCiAgICAgICAgcmVwKCLlhbHlpInph4/jgYLjgooiLCBsZW5ndGgobW9kZWxzX2J5X3BhcnR5X25fY292KSkKICAgICAgKQogICAgKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgImFtY2Vfbm9jb3ZfYW5kX2Nvdl9tb2RlbHMudHh0IikKICApCgogIGFtY2VfcGxvdF9jb3YgPC0gbWFrZV9hbWNlX3Bsb3RfZGYobW9kZWxzX2J5X3BhcnR5X25fY292KQogIHdyaXRlX2Nzdl9zYWZlbHkoYW1jZV9wbG90X2NvdiwgImFtY2VfY292X2NvZWZmaWNpZW50cy5jc3YiKQoKCiAgc3R1ZHlfbGFiZWwgPC0gIuWun+mokzHvvIgyMDIz5bm077yJIgoKICB0ZXJtX2xhYmVsc19mYWNldCA8LSB0ZXJtX2xhYmVscyAlPiUKICAgIG11dGF0ZSgKICAgICAgYXR0cmlidXRlX2ZhY2V0ID0gYXR0cmlidXRlCiAgICApCgogIGF0dHJpYnV0ZV9vcmRlcl9mYWNldCA8LSBjKAogICAgIuS4juWFmu+8j+mHjuWFmiIsCiAgICAi5pS/562W5L2N572uIiwKICAgICLorbDluK3mlbAiLAogICAgIkdEUOaIkOmVt+eOhyIsCiAgICAi5pel57WM5bmz5Z2HIiwKICAgICJDUEkiLAogICAgIuWksealreeOhyIKICApCgogIG1ha2VfYW1jZV9mYWNldF9kZiA8LSBmdW5jdGlvbihtb2RlbHMpIHsKICAgIGltYXBfZGZyKAogICAgICBtb2RlbHMsCiAgICAgIH4gdGlkeV9maXhlc3QoLngpICU+JQogICAgICAgIG11dGF0ZShwYXJ0eV9uID0gYXMuY2hhcmFjdGVyKC55KSkKICAgICkgJT4lCiAgICAgIGxlZnRfam9pbih0ZXJtX2xhYmVsc19mYWNldCwgYnkgPSAidGVybSIpICU+JQogICAgICBmaWx0ZXIoIWlzLm5hKGF0dHJpYnV0ZV9mYWNldCkpICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgICBjb25mLmxvd19wcCA9IGNvbmYubG93ICogMTAwLAogICAgICAgIGNvbmYuaGlnaF9wcCA9IGNvbmYuaGlnaCAqIDEwMCwKICAgICAgICBwYXJ0eV9uID0gZmFjdG9yKAogICAgICAgICAgcGFydHlfbiwKICAgICAgICAgIGxldmVscyA9IGMoIjIiLCAiMyIsICI0IiwgIjUiKSwKICAgICAgICAgIGxhYmVscyA9IGMoIjLmlL/lhZoiLCAiM+aUv+WFmiIsICI05pS/5YWaIiwgIjXmlL/lhZoiKQogICAgICAgICksCiAgICAgICAgYXR0cmlidXRlX2ZhY2V0ID0gZmFjdG9yKAogICAgICAgICAgYXR0cmlidXRlX2ZhY2V0LAogICAgICAgICAgbGV2ZWxzID0gYXR0cmlidXRlX29yZGVyX2ZhY2V0CiAgICAgICAgKSwKICAgICAgICBsYWJlbCA9IGZhY3RvcigKICAgICAgICAgIGxhYmVsLAogICAgICAgICAgbGV2ZWxzID0gcmV2KGxhYmVsX29yZGVyKQogICAgICAgICkKICAgICAgKQogIH0KCiAgYW1jZV9wbG90X2RmX2Nvdl9mYWNldCA8LSBtYWtlX2FtY2VfZmFjZXRfZGYobW9kZWxzX2J5X3BhcnR5X25fY292KQogIGFtY2VfcGxvdF9kZl9ub2Nvdl9mYWNldCA8LSBtYWtlX2FtY2VfZmFjZXRfZGYobW9kZWxzX2J5X3BhcnR5X25fbm9jb3YpCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBhbWNlX3Bsb3RfZGZfY292X2ZhY2V0LAogICAgImFtY2VfY292X2ZhY2V0X2NvZWZmaWNpZW50cy5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgYW1jZV9wbG90X2RmX25vY292X2ZhY2V0LAogICAgImFtY2Vfbm9jb3ZfZmFjZXRfY29lZmZpY2llbnRzLmNzdiIKICApCgoKICBwX2FtY2VfY292X2ZhY2V0IDwtIGdncGxvdCgKICAgIGFtY2VfcGxvdF9kZl9jb3ZfZmFjZXQsCiAgICBhZXMoCiAgICAgIHggPSBlc3RpbWF0ZV9wcCwKICAgICAgeSA9IGxhYmVsLAogICAgICBzaGFwZSA9IHBhcnR5X24sCiAgICAgIGxpbmV0eXBlID0gcGFydHlfbiwKICAgICAgZ3JvdXAgPSBwYXJ0eV9uCiAgICApCiAgKSArCiAgICBnZW9tX3ZsaW5lKAogICAgICB4aW50ZXJjZXB0ID0gMCwKICAgICAgbGluZXdpZHRoID0gMC40NSwKICAgICAgY29sb3IgPSAiZ3JleTM1IgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyaCgKICAgICAgYWVzKAogICAgICAgIHhtaW4gPSBjb25mLmxvd19wcCwKICAgICAgICB4bWF4ID0gY29uZi5oaWdoX3BwCiAgICAgICksCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwKICAgICAgaGVpZ2h0ID0gMC4xNiwKICAgICAgbGluZXdpZHRoID0gMC41NSwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fcG9pbnQoCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwKICAgICAgc2l6ZSA9IDIuNSwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgc3Ryb2tlID0gMC44CiAgICApICsKICAgIGZhY2V0X2dyaWQoCiAgICAgIGF0dHJpYnV0ZV9mYWNldCB+IC4sCiAgICAgIHNjYWxlcyA9ICJmcmVlX3kiLAogICAgICBzcGFjZSA9ICJmcmVlX3kiLAogICAgICBzd2l0Y2ggPSAieSIKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgIiBwcCIpLAogICAgICBicmVha3MgPSBzZXEoLTEyLCAxMiwgYnkgPSAyKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAi5pS/5YWa5pWw6YG45oqe6IKiIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMuaUv+WFmiIgPSAxNiwKICAgICAgICAiM+aUv+WFmiIgPSAxNywKICAgICAgICAiNOaUv+WFmiIgPSAxNSwKICAgICAgICAiNeaUv+WFmiIgPSAxCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICBuYW1lID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLmlL/lhZoiID0gInNvbGlkIiwKICAgICAgICAiM+aUv+WFmiIgPSAiZGFzaGVkIiwKICAgICAgICAiNOaUv+WFmiIgPSAiZG90dGVkIiwKICAgICAgICAiNeaUv+WFmiIgPSAiZG90ZGFzaCIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB4ID0gIumBuOaKnueiuueOh+OBruWkieWMliIsCiAgICAgIHkgPSBOVUxMCiAgICApICsKICAgIHRoZW1lX2J3KAogICAgICBiYXNlX3NpemUgPSAxMiwKICAgICAgYmFzZV9mYW1pbHkgPSAiWXUgR290aGljIgogICAgKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxNgogICAgICApLAogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KAogICAgICAgIGZpbGwgPSAiZ3JleTkyIiwKICAgICAgICBjb2xvciA9ICJncmV5NTUiCiAgICAgICksCiAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGFuZ2xlID0gMCwKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxMAogICAgICApLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQogICAgKQoKICBwcmludChwX2FtY2VfY292X2ZhY2V0KQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9jb3ZfZmFjZXRfbW9kZWwucG5nIiwKICAgIHBfYW1jZV9jb3ZfZmFjZXQsCiAgICB3aWR0aCA9IDEwLjUsCiAgICBoZWlnaHQgPSA4LjUKICApCgogIHBfYW1jZV9jb3ZfbWFpbiA8LSBwX2FtY2VfY292X2ZhY2V0CgoKICBtYWtlX2hlYXRtYXBfZGYgPC0gZnVuY3Rpb24oYW1jZV9wbG90X2RmKSB7CiAgICBoZWF0X2RmIDwtIGFtY2VfcGxvdF9kZiAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIGFic19hbWNlID0gYWJzKGVzdGltYXRlX3BwKSwKICAgICAgICBjdWVfdHlwZV9jb2RlID0gY2FzZV93aGVuKAogICAgICAgICAgY3VlX3R5cGUgPT0gIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIgfiAicGFydHkiLAogICAgICAgICAgY3VlX3R5cGUgPT0gIue1jOa4iOOBruaJi+OBjOOBi+OCiiIgfiAiZWNvbm9teSIsCiAgICAgICAgICBUUlVFIH4gIm90aGVyIgogICAgICAgICkKICAgICAgKSAlPiUKICAgICAgZ3JvdXBfYnkocGFydHlfbikgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICByYW5rX3dpdGhpbl9wYXJ0eSA9IG1pbl9yYW5rKGRlc2MoYWJzX2FtY2UpKSwKICAgICAgICBuX2luX2NvbCA9IG4oKSwKICAgICAgICByYW5rX3Njb3JlID0gaWZfZWxzZSgKICAgICAgICAgIG5faW5fY29sID09IDEsCiAgICAgICAgICAxLAogICAgICAgICAgMSAtIChyYW5rX3dpdGhpbl9wYXJ0eSAtIDEpIC8gKG5faW5fY29sIC0gMSkKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIHVuZ3JvdXAoKQoKICAgIHJvd19vcmRlcl9kZiA8LSBoZWF0X2RmICU+JQogICAgICBncm91cF9ieShsYWJlbCwgY3VlX3R5cGVfY29kZSkgJT4lCiAgICAgIHN1bW1hcmlzZSgKICAgICAgICBtZWFuX2Fic19hbWNlID0gbWVhbihhYnNfYW1jZSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIGFycmFuZ2UoZGVzYyhtZWFuX2Fic19hbWNlKSkKCiAgICByb3dfbGV2ZWxzIDwtIGFzLmNoYXJhY3Rlcihyb3dfb3JkZXJfZGYkbGFiZWwpCgogICAgaGVhdF9kZiA8LSBoZWF0X2RmICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgbGFiZWwgPSBmYWN0b3IoCiAgICAgICAgICBhcy5jaGFyYWN0ZXIobGFiZWwpLAogICAgICAgICAgbGV2ZWxzID0gcmV2KHJvd19sZXZlbHMpCiAgICAgICAgKQogICAgICApCgogICAgbGFiZWxfY29sb3JfbWFwIDwtIHJvd19vcmRlcl9kZiAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIGxhYmVsX21hcmtkb3duID0gY2FzZV93aGVuKAogICAgICAgICAgY3VlX3R5cGVfY29kZSA9PSAicGFydHkiIH4KICAgICAgICAgICAgcGFzdGUwKAogICAgICAgICAgICAgICI8c3BhbiBzdHlsZT0nY29sb3I6IzExMTExMTsnPiIsCiAgICAgICAgICAgICAgbGFiZWwsCiAgICAgICAgICAgICAgIjwvc3Bhbj4iCiAgICAgICAgICAgICksCiAgICAgICAgICBjdWVfdHlwZV9jb2RlID09ICJlY29ub215IiB+CiAgICAgICAgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAiPHNwYW4gc3R5bGU9J2NvbG9yOiM4QThBOEE7Jz4iLAogICAgICAgICAgICAgIGxhYmVsLAogICAgICAgICAgICAgICI8L3NwYW4+IgogICAgICAgICAgICApLAogICAgICAgICAgVFJVRSB+IGFzLmNoYXJhY3RlcihsYWJlbCkKICAgICAgICApCiAgICAgICkKCiAgICBsYWJlbF9tYXJrZG93bl92ZWMgPC0gc2V0TmFtZXMoCiAgICAgIGxhYmVsX2NvbG9yX21hcCRsYWJlbF9tYXJrZG93biwKICAgICAgYXMuY2hhcmFjdGVyKGxhYmVsX2NvbG9yX21hcCRsYWJlbCkKICAgICkKCiAgICBsaXN0KAogICAgICBoZWF0X2RmID0gaGVhdF9kZiwKICAgICAgbGFiZWxfbWFya2Rvd25fdmVjID0gbGFiZWxfbWFya2Rvd25fdmVjCiAgICApCiAgfQoKICBwbG90X2FtY2VfaGVhdG1hcCA8LSBmdW5jdGlvbigKICAgICAgaGVhdF9kZiwKICAgICAgbGFiZWxfbWFya2Rvd25fdmVjLAogICAgICB3aXRoX3JhbmsgPSBUUlVFLAogICAgICB0aXRsZV90ZXh0ID0gTlVMTCkgewoKICAgIGlmICh3aXRoX3JhbmspIHsKICAgICAgaGVhdF9kZiA8LSBoZWF0X2RmICU+JQogICAgICAgIG11dGF0ZSgKICAgICAgICAgIGNlbGxfbGFiZWwgPSBwYXN0ZTAoCiAgICAgICAgICAgIHNwcmludGYoIiUuMWYiLCBlc3RpbWF0ZV9wcCksCiAgICAgICAgICAgICJcbigiLAogICAgICAgICAgICByYW5rX3dpdGhpbl9wYXJ0eSwKICAgICAgICAgICAgIuS9jSkiCiAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgdGV4dF9zaXplIDwtIDMuMAogICAgICBsaW5laGVpZ2h0IDwtIDAuOQogICAgfSBlbHNlIHsKICAgICAgaGVhdF9kZiA8LSBoZWF0X2RmICU+JQogICAgICAgIG11dGF0ZSgKICAgICAgICAgIGNlbGxfbGFiZWwgPSBzcHJpbnRmKCIlLjFmIiwgZXN0aW1hdGVfcHApCiAgICAgICAgKQoKICAgICAgdGV4dF9zaXplIDwtIDMuNAogICAgICBsaW5laGVpZ2h0IDwtIDEuMAogICAgfQoKICAgIGdncGxvdCgKICAgICAgaGVhdF9kZiwKICAgICAgYWVzKAogICAgICAgIHggPSBwYXJ0eV9uLAogICAgICAgIHkgPSBsYWJlbCwKICAgICAgICBmaWxsID0gcmFua19zY29yZQogICAgICApCiAgICApICsKICAgICAgZ2VvbV90aWxlKAogICAgICAgIGNvbG9yID0gIndoaXRlIiwKICAgICAgICBsaW5ld2lkdGggPSAwLjcKICAgICAgKSArCiAgICAgIGdlb21fdGV4dCgKICAgICAgICBhZXMobGFiZWwgPSBjZWxsX2xhYmVsKSwKICAgICAgICBzaXplID0gdGV4dF9zaXplLAogICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICBsaW5laGVpZ2h0ID0gbGluZWhlaWdodAogICAgICApICsKICAgICAgc2NhbGVfeV9kaXNjcmV0ZSgKICAgICAgICBsYWJlbHMgPSBsYWJlbF9tYXJrZG93bl92ZWMKICAgICAgKSArCiAgICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQoCiAgICAgICAgbG93ID0gImdyZXk5NSIsCiAgICAgICAgaGlnaCA9ICJncmV5MTUiLAogICAgICAgIGxpbWl0cyA9IGMoMCwgMSksCiAgICAgICAgYnJlYWtzID0gYygwLCAwLjI1LCAwLjUwLCAwLjc1LCAxLjAwKSwKICAgICAgICBsYWJlbHMgPSBjKCLkvY4iLCAiIiwgIiIsICIiLCAi6auYIiksCiAgICAgICAgbmFtZSA9ICLliJflhoXpoIbkvY1cbu+8iOa/g+OBhOOBu+OBqemrmOS9je+8iSIKICAgICAgKSArCiAgICAgIGxhYnMoCiAgICAgICAgdGl0bGUgPSB0aXRsZV90ZXh0LAogICAgICAgIHggPSAi5pS/5YWa5pWw6YG45oqe6IKiIiwKICAgICAgICB5ID0gTlVMTAogICAgICApICsKICAgICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTIpICsKICAgICAgdGhlbWUoCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRleHQueSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bihzaXplID0gOSksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICkKICB9CgogIGhlYXRtYXBfaW5wdXQgPC0gbWFrZV9oZWF0bWFwX2RmKGFtY2VfcGxvdF9jb3YpCgogIHBfaGVhdF9hbWNlX21peGVkIDwtIHBsb3RfYW1jZV9oZWF0bWFwKAogICAgaGVhdG1hcF9pbnB1dCRoZWF0X2RmLAogICAgaGVhdG1hcF9pbnB1dCRsYWJlbF9tYXJrZG93bl92ZWMsCiAgICB3aXRoX3JhbmsgPSBGQUxTRSwKICAgIHRpdGxlX3RleHQgPSBOVUxMCiAgKQoKICBwcmludChwX2hlYXRfYW1jZV9taXhlZCkKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfaGVhdG1hcF9taXhlZF9yYW5rX2NvbG9yZWRfbGFiZWxzLnBuZyIsCiAgICBwX2hlYXRfYW1jZV9taXhlZCwKICAgIHdpZHRoID0gOC44LAogICAgaGVpZ2h0ID0gOC44CiAgKQoKICBwX2hlYXRfYW1jZV9taXhlZF9yYW5rbGFiZWwgPC0gcGxvdF9hbWNlX2hlYXRtYXAoCiAgICBoZWF0bWFwX2lucHV0JGhlYXRfZGYsCiAgICBoZWF0bWFwX2lucHV0JGxhYmVsX21hcmtkb3duX3ZlYywKICAgIHdpdGhfcmFuayA9IFRSVUUsCiAgICB0aXRsZV90ZXh0ID0gTlVMTAogICkKCiAgcHJpbnQocF9oZWF0X2FtY2VfbWl4ZWRfcmFua2xhYmVsKQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9oZWF0bWFwX21peGVkX3JhbmtfY29sb3JlZF9sYWJlbHNfd2l0aHJhbmsucG5nIiwKICAgIHBfaGVhdF9hbWNlX21peGVkX3JhbmtsYWJlbCwKICAgIHdpZHRoID0gOC44LAogICAgaGVpZ2h0ID0gOC44CiAgKQoKICBwX2hlYXRfYW1jZSA8LSBwX2hlYXRfYW1jZV9taXhlZAogIHBfaGVhdF9hbWNlX3JhbmsgPC0gcF9oZWF0X2FtY2VfbWl4ZWRfcmFua2xhYmVsCgoKICBwX2FtY2VfZmFjZXRfbm9jb3YgPC0gZ2dwbG90KAogICAgYW1jZV9wbG90X2RmX25vY292X2ZhY2V0LAogICAgYWVzKAogICAgICB4ID0gZXN0aW1hdGVfcHAsCiAgICAgIHkgPSBsYWJlbCwKICAgICAgc2hhcGUgPSBwYXJ0eV9uLAogICAgICBsaW5ldHlwZSA9IHBhcnR5X24sCiAgICAgIGdyb3VwID0gcGFydHlfbgogICAgKQogICkgKwogICAgZ2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImdyZXkzNSIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcmgoCiAgICAgIGFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIGhlaWdodCA9IDAuMTYsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX3BvaW50KAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIHNpemUgPSAyLjUsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIHN0cm9rZSA9IDAuOAogICAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBhdHRyaWJ1dGVfZmFjZXQgfiAuLAogICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgc3BhY2UgPSAiZnJlZV95IiwKICAgICAgc3dpdGNoID0gInkiCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIgcHAiKSwKICAgICAgYnJlYWtzID0gc2VxKC0xMiwgMTIsIGJ5ID0gMikKICAgICkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKAogICAgICBuYW1lID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLmlL/lhZoiID0gMTYsCiAgICAgICAgIjPmlL/lhZoiID0gMTcsCiAgICAgICAgIjTmlL/lhZoiID0gMTUsCiAgICAgICAgIjXmlL/lhZoiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICLmlL/lhZrmlbDpgbjmip7ogqIiLAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIy5pS/5YWaIiA9ICJzb2xpZCIsCiAgICAgICAgIjPmlL/lhZoiID0gImRhc2hlZCIsCiAgICAgICAgIjTmlL/lhZoiID0gImRvdHRlZCIsCiAgICAgICAgIjXmlL/lhZoiID0gImRvdGRhc2giCiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgeCA9ICLpgbjmip7norrnjofjga7lpInljJYiLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSAxMikgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTYKICAgICAgKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICAgICkKCiAgcHJpbnQocF9hbWNlX2ZhY2V0X25vY292KQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9mYWNldF9ub2Nvdi5wbmciLAogICAgcF9hbWNlX2ZhY2V0X25vY292LAogICAgd2lkdGggPSAxMC41LAogICAgaGVpZ2h0ID0gOQogICkKCiAgcF9hbWNlX25vY292X2FwcGVuZGl4IDwtIHBfYW1jZV9mYWNldF9ub2NvdgoKCiAgcF9pbnRlcmFjdGlvbiA8LSBnZ3Bsb3QoCiAgICBpbnRlcmFjdGlvbl9wbG90X2RmLAogICAgYWVzKAogICAgICB4ID0gZXN0aW1hdGVfcHAsCiAgICAgIHkgPSBsYWJlbCwKICAgICAgc2hhcGUgPSBwYXJ0eV9uX2xhYmVsLAogICAgICBsaW5ldHlwZSA9IHBhcnR5X25fbGFiZWwsCiAgICAgIGdyb3VwID0gcGFydHlfbl9sYWJlbAogICAgKQogICkgKwogICAgZ2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImdyZXkzNSIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcmgoCiAgICAgIGFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIGhlaWdodCA9IDAuMTYsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX3BvaW50KAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIHNpemUgPSAyLjUsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIHN0cm9rZSA9IDAuOAogICAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBhdHRyaWJ1dGUgfiAuLAogICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgc3BhY2UgPSAiZnJlZV95IiwKICAgICAgc3dpdGNoID0gInkiCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIgcHAiKSwKICAgICAgYnJlYWtzID0gc2VxKC04LCA4LCBieSA9IDIpCiAgICApICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICIy5pS/5YWa44Gu5aC05ZCI44Go44Gu5q+U6LyDIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiM+aUv+WFmiIgPSAxNywKICAgICAgICAiNOaUv+WFmiIgPSAxNSwKICAgICAgICAiNeaUv+WFmiIgPSAxCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICBuYW1lID0gIjLmlL/lhZrjga7loLTlkIjjgajjga7mr5TovIMiLAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIz5pS/5YWaIiA9ICJkYXNoZWQiLAogICAgICAgICI05pS/5YWaIiA9ICJkb3R0ZWQiLAogICAgICAgICI15pS/5YWaIiA9ICJkb3RkYXNoIgogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHggPSAiMuaUv+WFmuadoeS7tuOBqOOBruW3riIsCiAgICAgIHkgPSBOVUxMCiAgICApICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxNQogICAgICApLAogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KAogICAgICAgIGZpbGwgPSAiZ3JleTkyIiwKICAgICAgICBjb2xvciA9ICJncmV5NTUiCiAgICAgICksCiAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGFuZ2xlID0gMCwKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxMAogICAgICApLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQogICAgKQoKICBwcmludChwX2ludGVyYWN0aW9uKQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9pbnRlcmFjdGlvbl9kaWZmZXJlbmNlX2Zyb21fMnBhcnR5LnBuZyIsCiAgICBwX2ludGVyYWN0aW9uLAogICAgd2lkdGggPSAxMC41LAogICAgaGVpZ2h0ID0gOQogICkKCgogIGNvbmpvaW50X2Nsb2dpdCA8LSBjb25qb2ludF9hbGxfbSAlPiUKICAgIG11dGF0ZSgKICAgICAgc2VsZWN0ZWQgPSBhcy5pbnRlZ2VyKHNlbGVjdGVkKSwKICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoSUQpLAogICAgICB0YXNrX2lkID0gZmFjdG9yKHRhc2tfaWQpLAogICAgICBwb2xpY3lfcG9zaXRpb24gPSByZWxldmVsX2lmX3ByZXNlbnQoCiAgICAgICAgcG9saWN5X3Bvc2l0aW9uLAogICAgICAgICLkuK3pgZMiCiAgICAgICksCiAgICAgIGdvdmVybm1lbnRfc3RhdHVzID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIGdvdmVybm1lbnRfc3RhdHVzLAogICAgICAgICLph47lhZoiCiAgICAgICksCiAgICAgIGdkcF9ncm93dGggPSByZWxldmVsX2lmX3ByZXNlbnQoCiAgICAgICAgZ2RwX2dyb3d0aCwKICAgICAgICAiR0RQ5oiQ6ZW3546HwrEw77yFIgogICAgICApLAogICAgICBuaWtrZWkgPSByZWxldmVsX2lmX3ByZXNlbnQoCiAgICAgICAgbmlra2VpLAogICAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiCiAgICAgICksCiAgICAgIHNlYXRzID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIHNlYXRzLAogICAgICAgICIxMOS7peS4iyIKICAgICAgKSwKICAgICAgY3BpID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIGNwaSwKICAgICAgICAiQ1BJ5YmN5pyf5q+UwrEw44Od44Kk44Oz44OIIgogICAgICApLAogICAgICB1bmVtcGxveW1lbnQgPSByZWxldmVsX2lmX3ByZXNlbnQoCiAgICAgICAgdW5lbXBsb3ltZW50LAogICAgICAgICLlpLHmpa3njofliY3mnJ/mr5TCsTDvvIUiCiAgICAgICkKICAgICkKCiAgZm9ybXVsYV9jbG9naXRfbm9jb3YgPC0gYXMuZm9ybXVsYSgKICAgIHBhc3RlMCgKICAgICAgInNlbGVjdGVkIH4gIiwKICAgICAgcGFzdGUoYXR0cl90ZXJtcywgY29sbGFwc2UgPSAiICsgIiksCiAgICAgICIgKyBzdHJhdGEodGFza19pZCkgKyBjbHVzdGVyKElEKSIKICAgICkKICApCgogIHJ1bl9jbG9naXRfbm9jb3YgPC0gZnVuY3Rpb24oZGF0KSB7CiAgICBzdXJ2aXZhbDo6Y2xvZ2l0KAogICAgICBmb3JtdWxhX2Nsb2dpdF9ub2NvdiwKICAgICAgZGF0YSA9IGRhdCwKICAgICAgbWV0aG9kID0gImVmcm9uIgogICAgKQogIH0KCiAgbW9kZWxzX2Nsb2dpdF9ub2NvdiA8LSBjb25qb2ludF9jbG9naXQgJT4lCiAgICBzcGxpdCguJHBhcnR5X24pICU+JQogICAgbWFwKHJ1bl9jbG9naXRfbm9jb3YpCgogIGNhcHR1cmUub3V0cHV0KAogICAgbGFwcGx5KG1vZGVsc19jbG9naXRfbm9jb3YsIHN1bW1hcnkpLAogICAgZmlsZSA9IGZpbGUucGF0aCgKICAgICAgb3V0cHV0X2RpciwKICAgICAgImNvbmRpdGlvbmFsX2xvZ2l0X21vZGVscy50eHQiCiAgICApCiAgKQoKICB0aWR5X2Nsb2dpdCA8LSBmdW5jdGlvbihtb2RlbCkgewogICAgcyA8LSBzdW1tYXJ5KG1vZGVsKQogICAgY3QgPC0gYXMuZGF0YS5mcmFtZShzJGNvZWZmaWNpZW50cykKICAgIGN0JHRlcm0gPC0gcm93bmFtZXMoY3QpCgogICAgc2VfY29sIDwtIGlmICgicm9idXN0IHNlIiAlaW4lIG5hbWVzKGN0KSkgewogICAgICAicm9idXN0IHNlIgogICAgfSBlbHNlIGlmICgic2UoY29lZikiICVpbiUgbmFtZXMoY3QpKSB7CiAgICAgICJzZShjb2VmKSIKICAgIH0gZWxzZSB7CiAgICAgIHN0b3AoIkNoZWNrIGNsb2dpdCIpCiAgICB9CgogICAgcF9jb2wgPC0gaWYgKCJQcig+fHp8KSIgJWluJSBuYW1lcyhjdCkpIHsKICAgICAgIlByKD58enwpIgogICAgfSBlbHNlIGlmICgiUHIoPnx0fCkiICVpbiUgbmFtZXMoY3QpKSB7CiAgICAgICJQcig+fHR8KSIKICAgIH0gZWxzZSB7CiAgICAgIE5BX2NoYXJhY3Rlcl8KICAgIH0KCiAgICBjdCAlPiUKICAgICAgYXNfdGliYmxlKCkgJT4lCiAgICAgIHRyYW5zbXV0ZSgKICAgICAgICB0ZXJtID0gdGVybSwKICAgICAgICBlc3RpbWF0ZSA9IGNvZWYsCiAgICAgICAgc3RkLmVycm9yID0gLmRhdGFbW3NlX2NvbF1dLAogICAgICAgIHAudmFsdWUgPSBpZiAoIWlzLm5hKHBfY29sKSkgewogICAgICAgICAgLmRhdGFbW3BfY29sXV0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgTkFfcmVhbF8KICAgICAgICB9LAogICAgICAgIGNvbmYubG93ID0gZXN0aW1hdGUgLSAxLjk2ICogc3RkLmVycm9yLAogICAgICAgIGNvbmYuaGlnaCA9IGVzdGltYXRlICsgMS45NiAqIHN0ZC5lcnJvciwKICAgICAgICBvZGRzX3JhdGlvID0gZXhwKGVzdGltYXRlKSwKICAgICAgICBvZGRzX3JhdGlvX2xvdyA9IGV4cChjb25mLmxvdyksCiAgICAgICAgb2Rkc19yYXRpb19oaWdoID0gZXhwKGNvbmYuaGlnaCkKICAgICAgKQogIH0KCiAgY2xvZ2l0X3Bsb3RfZGYgPC0gaW1hcF9kZnIoCiAgICBtb2RlbHNfY2xvZ2l0X25vY292LAogICAgfiB0aWR5X2Nsb2dpdCgueCkgJT4lCiAgICAgIG11dGF0ZShwYXJ0eV9uID0gYXMuY2hhcmFjdGVyKC55KSkKICApICU+JQogICAgbGVmdF9qb2luKHRlcm1fbGFiZWxzLCBieSA9ICJ0ZXJtIikgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGF0dHJpYnV0ZSkpICU+JQogICAgbXV0YXRlKAogICAgICBwYXJ0eV9uID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gYygiMiIsICIzIiwgIjQiLCAiNSIpLAogICAgICAgIGxhYmVscyA9IGMoIjLmlL/lhZoiLCAiM+aUv+WFmiIsICI05pS/5YWaIiwgIjXmlL/lhZoiKQogICAgICApLAogICAgICBsYWJlbCA9IGZhY3RvcigKICAgICAgICBsYWJlbCwKICAgICAgICBsZXZlbHMgPSByZXYobGFiZWxfb3JkZXIpCiAgICAgICkKICAgICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIGNsb2dpdF9wbG90X2RmLAogICAgImNvbmRpdGlvbmFsX2xvZ2l0X2NvZWZmaWNpZW50cy5jc3YiCiAgKQoKCiAgcF9jbG9naXRfb3IgPC0gZ2dwbG90KAogICAgY2xvZ2l0X3Bsb3RfZGYsCiAgICBhZXMoCiAgICAgIHggPSBvZGRzX3JhdGlvLAogICAgICB5ID0gbGFiZWwsCiAgICAgIHNoYXBlID0gcGFydHlfbiwKICAgICAgbGluZXR5cGUgPSBwYXJ0eV9uLAogICAgICBncm91cCA9IHBhcnR5X24KICAgICkKICApICsKICAgIGdlb21fdmxpbmUoCiAgICAgIHhpbnRlcmNlcHQgPSAxLAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICBsaW5ld2lkdGggPSAwLjQ1LAogICAgICBjb2xvciA9ICJncmV5MzUiCiAgICApICsKICAgIGdlb21fZXJyb3JiYXJoKAogICAgICBhZXMoCiAgICAgICAgeG1pbiA9IG9kZHNfcmF0aW9fbG93LAogICAgICAgIHhtYXggPSBvZGRzX3JhdGlvX2hpZ2gKICAgICAgKSwKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzIpLAogICAgICBoZWlnaHQgPSAwLjE1LAogICAgICBsaW5ld2lkdGggPSAwLjQ1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzIpLAogICAgICBzaXplID0gMi40LAogICAgICBzdHJva2UgPSAwLjcsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV94X2xvZzEwKAogICAgICBicmVha3MgPSBjKAogICAgICAgIDAuNiwKICAgICAgICAwLjgsCiAgICAgICAgMS4wLAogICAgICAgIDEuMjUsCiAgICAgICAgMS41LAogICAgICAgIDIuMAogICAgICApLAogICAgICBsYWJlbHMgPSBjKAogICAgICAgICIwLjYiLAogICAgICAgICIwLjgiLAogICAgICAgICIxLjAiLAogICAgICAgICIxLjI1IiwKICAgICAgICAiMS41IiwKICAgICAgICAiMi4wIgogICAgICApCiAgICApICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMuaUv+WFmiIgPSAxNiwKICAgICAgICAiM+aUv+WFmiIgPSAxNywKICAgICAgICAiNOaUv+WFmiIgPSAxNSwKICAgICAgICAiNeaUv+WFmiIgPSAxCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIy5pS/5YWaIiA9ICJzb2xpZCIsCiAgICAgICAgIjPmlL/lhZoiID0gImRhc2hlZCIsCiAgICAgICAgIjTmlL/lhZoiID0gImRvdGRhc2giLAogICAgICAgICI15pS/5YWaIiA9ICJ0d29kYXNoIgogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHggPSAi44Kq44OD44K65q+UIiwKICAgICAgeSA9IE5VTEwsCiAgICAgIHNoYXBlID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIsCiAgICAgIGxpbmV0eXBlID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIKICAgICkgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTIpICsKICAgIHRoZW1lKAogICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkKICAgICkKCiAgcHJpbnQocF9jbG9naXRfb3IpCgogIHNhdmVfcGxvdCgKICAgICJjbG9naXRfb2Rkc3JhdGlvX25vY292LnBuZyIsCiAgICBwX2Nsb2dpdF9vciwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDguNQogICkKCgogIHJlbGF0aXZlX2N1ZV9tYXAgPC0gYygKICAgIHBvbGljeV9wb3NpdGlvbiA9ICJwYXJ0eSIsCiAgICBnb3Zlcm5tZW50X3N0YXR1cyA9ICJwYXJ0eSIsCiAgICBzZWF0cyA9ICJwYXJ0eSIsCiAgICBnZHBfZ3Jvd3RoID0gImVjb25vbWljIiwKICAgIG5pa2tlaSA9ICJlY29ub21pYyIsCiAgICBjcGkgPSAiZWNvbm9taWMiLAogICAgdW5lbXBsb3ltZW50ID0gImVjb25vbWljIgogICkKCiAgbWVhbl9hYnNvbHV0ZV9wYWlyd2lzZV9kaWZmZXJlbmNlIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0geFtpcy5maW5pdGUoeCldCgogICAgaWYgKGxlbmd0aCh4KSA8IDIpIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHBhaXJ3aXNlX2RpZmZlcmVuY2VzIDwtIGNvbWJuKAogICAgICB4LAogICAgICAyLAogICAgICBGVU4gPSBmdW5jdGlvbih6KSBhYnMoelsxXSAtIHpbMl0pCiAgICApCgogICAgbWVhbihwYWlyd2lzZV9kaWZmZXJlbmNlcykKICB9CgogIGxpbmVhcl9zbG9wZSA8LSBmdW5jdGlvbih5LCB4KSB7CiAgICBrZWVwIDwtIGlzLmZpbml0ZSh5KSAmIGlzLmZpbml0ZSh4KQogICAgeSA8LSB5W2tlZXBdCiAgICB4IDwtIHhba2VlcF0KCiAgICBpZiAobGVuZ3RoKHkpIDwgMiB8fCBsZW5ndGgodW5pcXVlKHgpKSA8IDIpIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHVubmFtZShjb2VmKGxtKHkgfiB4KSlbMl0pCiAgfQoKICBib290c3RyYXBfdHdvX3NpZGVkX3AgPC0gZnVuY3Rpb24oeCkgewogICAgeCA8LSB4W2lzLmZpbml0ZSh4KV0KICAgIEJfdmFsaWQgPC0gbGVuZ3RoKHgpCgogICAgaWYgKEJfdmFsaWQgPT0gMCkgewogICAgICByZXR1cm4oTkFfcmVhbF8pCiAgICB9CgogICAgcF9sb3dlciA8LSAoMSArIHN1bSh4IDw9IDApKSAvIChCX3ZhbGlkICsgMSkKICAgIHBfdXBwZXIgPC0gKDEgKyBzdW0oeCA+PSAwKSkgLyAoQl92YWxpZCArIDEpCgogICAgbWluKDEsIDIgKiBtaW4ocF9sb3dlciwgcF91cHBlcikpCiAgfQoKICBzYWZlX3F1YW50aWxlIDwtIGZ1bmN0aW9uKHgsIHByb2JhYmlsaXR5KSB7CiAgICB4IDwtIHhbaXMuZmluaXRlKHgpXQoKICAgIGlmIChsZW5ndGgoeCkgPT0gMCkgewogICAgICByZXR1cm4oTkFfcmVhbF8pCiAgICB9CgogICAgdW5uYW1lKAogICAgICBxdWFudGlsZSgKICAgICAgICB4LAogICAgICAgIHByb2JzID0gcHJvYmFiaWxpdHksCiAgICAgICAgdHlwZSA9IDYsCiAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICkKICAgICkKICB9CgogIHByZXBhcmVfcmVsYXRpdmVfY3VlX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKGRhdGEsIGN1ZV9tYXApIHsKICAgIGF0dHJpYnV0ZXMgPC0gbmFtZXMoY3VlX21hcCkKCiAgICByZXF1aXJlZF9jb2x1bW5zIDwtIGMoCiAgICAgICJJRCIsCiAgICAgICJwYXJ0eV9uIiwKICAgICAgInNlbGVjdGVkIiwKICAgICAgYXR0cmlidXRlcwogICAgKQoKICAgIG1pc3NpbmdfY29sdW1ucyA8LSBzZXRkaWZmKAogICAgICByZXF1aXJlZF9jb2x1bW5zLAogICAgICBuYW1lcyhkYXRhKQogICAgKQoKICAgIGlmIChsZW5ndGgobWlzc2luZ19jb2x1bW5zKSA+IDApIHsKICAgICAgc3RvcCgiQ2hlY2sgcmVsYXRpdmUgd2VpZ2h0IikKICAgIH0KCiAgICBpZiAoIWFsbCh1bm5hbWUoY3VlX21hcCkgJWluJSBjKCJwYXJ0eSIsICJlY29ub21pYyIpKSkgewogICAgICBzdG9wKCJDaGVjayByZWxhdGl2ZSB3ZWlnaHQiKQogICAgfQoKICAgIGFuYWx5c2lzX2RhdGEgPC0gZGF0YSAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELAogICAgICAgIHBhcnR5X24sCiAgICAgICAgc2VsZWN0ZWQsCiAgICAgICAgYWxsX29mKGF0dHJpYnV0ZXMpCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCiAgICAgICAgcGFydHlfbiA9IGFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHBhcnR5X24pKSwKICAgICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoc2VsZWN0ZWQpLAogICAgICAgIGFjcm9zcygKICAgICAgICAgIGFsbF9vZihhdHRyaWJ1dGVzKSwKICAgICAgICAgIGFzLmNoYXJhY3RlcgogICAgICAgICkKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKAogICAgICAgICFpcy5uYShJRCksCiAgICAgICAgcGFydHlfbiAlaW4lIDI6NSwKICAgICAgICBzZWxlY3RlZCAlaW4lIGMoMEwsIDFMKQogICAgICApCgogICAgb2JzZXJ2ZWRfY29uZGl0aW9ucyA8LSBzb3J0KAogICAgICB1bmlxdWUoYW5hbHlzaXNfZGF0YSRwYXJ0eV9uKQogICAgKQoKICAgIGlmICghaWRlbnRpY2FsKG9ic2VydmVkX2NvbmRpdGlvbnMsIDI6NSkpIHsKICAgICAgc3RvcCgiQ2hlY2siKQogICAgfQoKICAgIGxvbmdfZGF0YSA8LSBhbmFseXNpc19kYXRhICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihhdHRyaWJ1dGVzKSwKICAgICAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLAogICAgICAgIHZhbHVlc190byA9ICJsZXZlbCIKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKAogICAgICAgICFpcy5uYShsZXZlbCksCiAgICAgICAgbGV2ZWwgIT0gIiIKICAgICAgKQoKICAgIGV4cGVjdGVkX2NlbGxzIDwtIGxvbmdfZGF0YSAlPiUKICAgICAgZGlzdGluY3QoCiAgICAgICAgYXR0cmlidXRlLAogICAgICAgIGxldmVsCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBhdHRyaWJ1dGVfb3JkZXIgPSBtYXRjaCgKICAgICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICAgIGF0dHJpYnV0ZXMKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIGFycmFuZ2UoCiAgICAgICAgYXR0cmlidXRlX29yZGVyLAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbAogICAgICApICU+JQogICAgICBzZWxlY3QoLWF0dHJpYnV0ZV9vcmRlcikgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBjZWxsX2tleSA9IHBhc3RlKAogICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgbGV2ZWwsCiAgICAgICAgICBzZXAgPSAiXHIiCiAgICAgICAgKQogICAgICApCgogICAgcmVzcG9uZGVudF9jZWxsIDwtIGxvbmdfZGF0YSAlPiUKICAgICAgZ3JvdXBfYnkoCiAgICAgICAgcGFydHlfbiwKICAgICAgICBJRCwKICAgICAgICBhdHRyaWJ1dGUsCiAgICAgICAgbGV2ZWwKICAgICAgKSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIHlfc3VtID0gc3VtKHNlbGVjdGVkKSwKICAgICAgICBuX29icyA9IG4oKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBjZWxsX2tleSA9IHBhc3RlKAogICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgbGV2ZWwsCiAgICAgICAgICBzZXAgPSAiXHIiCiAgICAgICAgKQogICAgICApCgogICAgY29uZGl0aW9uX29iamVjdHMgPC0gbGFwcGx5KAogICAgICAyOjUsCiAgICAgIGZ1bmN0aW9uKG5fdmFsdWUpIHsKICAgICAgICBjb25kaXRpb25fZGF0YSA8LSByZXNwb25kZW50X2NlbGwgJT4lCiAgICAgICAgICBmaWx0ZXIoCiAgICAgICAgICAgIHBhcnR5X24gPT0gbl92YWx1ZQogICAgICAgICAgKQoKICAgICAgICBpZF92YWx1ZXMgPC0gc29ydCgKICAgICAgICAgIHVuaXF1ZShjb25kaXRpb25fZGF0YSRJRCkKICAgICAgICApCiAgICAgICAgbl9pZHMgPC0gbGVuZ3RoKGlkX3ZhbHVlcykKICAgICAgICBuX2NlbGxzIDwtIG5yb3coZXhwZWN0ZWRfY2VsbHMpCgogICAgICAgIGlmIChuX2lkcyA9PSAwKSB7CiAgICAgICAgICBzdG9wKCJDaGVjayIpCiAgICAgICAgfQoKICAgICAgICB5X21hdHJpeCA8LSBtYXRyaXgoCiAgICAgICAgICAwLAogICAgICAgICAgbnJvdyA9IG5faWRzLAogICAgICAgICAgbmNvbCA9IG5fY2VsbHMsCiAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoCiAgICAgICAgICAgIGlkX3ZhbHVlcywKICAgICAgICAgICAgZXhwZWN0ZWRfY2VsbHMkY2VsbF9rZXkKICAgICAgICAgICkKICAgICAgICApCgogICAgICAgIG5fbWF0cml4IDwtIG1hdHJpeCgKICAgICAgICAgIDAsCiAgICAgICAgICBucm93ID0gbl9pZHMsCiAgICAgICAgICBuY29sID0gbl9jZWxscywKICAgICAgICAgIGRpbW5hbWVzID0gbGlzdCgKICAgICAgICAgICAgaWRfdmFsdWVzLAogICAgICAgICAgICBleHBlY3RlZF9jZWxscyRjZWxsX2tleQogICAgICAgICAgKQogICAgICAgICkKCiAgICAgICAgcm93X2luZGV4IDwtIG1hdGNoKAogICAgICAgICAgY29uZGl0aW9uX2RhdGEkSUQsCiAgICAgICAgICBpZF92YWx1ZXMKICAgICAgICApCiAgICAgICAgY29sdW1uX2luZGV4IDwtIG1hdGNoKAogICAgICAgICAgY29uZGl0aW9uX2RhdGEkY2VsbF9rZXksCiAgICAgICAgICBleHBlY3RlZF9jZWxscyRjZWxsX2tleQogICAgICAgICkKCiAgICAgICAgeV9tYXRyaXhbY2JpbmQocm93X2luZGV4LCBjb2x1bW5faW5kZXgpXSA8LQogICAgICAgICAgY29uZGl0aW9uX2RhdGEkeV9zdW0KICAgICAgICBuX21hdHJpeFtjYmluZChyb3dfaW5kZXgsIGNvbHVtbl9pbmRleCldIDwtCiAgICAgICAgICBjb25kaXRpb25fZGF0YSRuX29icwoKICAgICAgICBpZiAoYW55KGNvbFN1bXMobl9tYXRyaXgpID09IDApKSB7CiAgICAgICAgICBtaXNzaW5nX2NlbGxzIDwtIGV4cGVjdGVkX2NlbGxzJGNlbGxfa2V5WwogICAgICAgICAgICBjb2xTdW1zKG5fbWF0cml4KSA9PSAwCiAgICAgICAgICBdCgogICAgICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICAgICAgfQoKICAgICAgICBsaXN0KAogICAgICAgICAgcGFydHlfbiA9IG5fdmFsdWUsCiAgICAgICAgICBpZHMgPSBpZF92YWx1ZXMsCiAgICAgICAgICBjZWxsX2luZm8gPSBleHBlY3RlZF9jZWxscywKICAgICAgICAgIHlfbWF0cml4ID0geV9tYXRyaXgsCiAgICAgICAgICBuX21hdHJpeCA9IG5fbWF0cml4CiAgICAgICAgKQogICAgICB9CiAgICApCgogICAgbmFtZXMoY29uZGl0aW9uX29iamVjdHMpIDwtIGFzLmNoYXJhY3RlcigyOjUpCgogICAgbGlzdCgKICAgICAgY3VlX21hcCA9IGN1ZV9tYXAsCiAgICAgIGF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzLAogICAgICBjb25kaXRpb25zID0gY29uZGl0aW9uX29iamVjdHMKICAgICkKICB9CgogIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzIDwtIGZ1bmN0aW9uKAogICAgICBwcmVwYXJlZCwKICAgICAgY2x1c3Rlcl93ZWlnaHRzID0gTlVMTAogICkgewogICAgY29uZGl0aW9uX3Jlc3VsdHMgPC0gbGFwcGx5KAogICAgICBuYW1lcyhwcmVwYXJlZCRjb25kaXRpb25zKSwKICAgICAgZnVuY3Rpb24oY29uZGl0aW9uX25hbWUpIHsKICAgICAgICBvYmplY3QgPC0gcHJlcGFyZWQkY29uZGl0aW9uc1tbY29uZGl0aW9uX25hbWVdXQoKICAgICAgICBpZiAoaXMubnVsbChjbHVzdGVyX3dlaWdodHMpKSB7CiAgICAgICAgICB3ZWlnaHRzIDwtIHJlcCgKICAgICAgICAgICAgMSwKICAgICAgICAgICAgbGVuZ3RoKG9iamVjdCRpZHMpCiAgICAgICAgICApCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHdlaWdodHMgPC0gY2x1c3Rlcl93ZWlnaHRzW1tjb25kaXRpb25fbmFtZV1dCiAgICAgICAgfQoKICAgICAgICBpZiAobGVuZ3RoKHdlaWdodHMpICE9IGxlbmd0aChvYmplY3QkaWRzKSkgewogICAgICAgICAgc3RvcCgiQ2hlY2siKQogICAgICAgIH0KCiAgICAgICAgbnVtZXJhdG9yIDwtIGFzLm51bWVyaWMoCiAgICAgICAgICBjcm9zc3Byb2QoCiAgICAgICAgICAgIHdlaWdodHMsCiAgICAgICAgICAgIG9iamVjdCR5X21hdHJpeAogICAgICAgICAgKQogICAgICAgICkKCiAgICAgICAgZGVub21pbmF0b3IgPC0gYXMubnVtZXJpYygKICAgICAgICAgIGNyb3NzcHJvZCgKICAgICAgICAgICAgd2VpZ2h0cywKICAgICAgICAgICAgb2JqZWN0JG5fbWF0cml4CiAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBpZiAoYW55KGRlbm9taW5hdG9yIDw9IDApKSB7CiAgICAgICAgICBzdG9wKCJDaGVjayBhdHRyaWJ1dGVzIikKICAgICAgICB9CgogICAgICAgIG1hcmdpbmFsX21lYW5zIDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yCgogICAgICAgIG1tX3RhYmxlIDwtIG9iamVjdCRjZWxsX2luZm8gJT4lCiAgICAgICAgICB0cmFuc211dGUoCiAgICAgICAgICAgIHBhcnR5X24gPSBvYmplY3QkcGFydHlfbiwKICAgICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgICBsZXZlbCwKICAgICAgICAgICAgbWFyZ2luYWxfbWVhbiA9IG1hcmdpbmFsX21lYW5zCiAgICAgICAgICApCgogICAgICAgIGF0dHJpYnV0ZV90YWJsZSA8LSBtbV90YWJsZSAlPiUKICAgICAgICAgIGdyb3VwX2J5KAogICAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgICBhdHRyaWJ1dGUKICAgICAgICAgICkgJT4lCiAgICAgICAgICBzdW1tYXJpc2UoCiAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgICAgICAgIG1lYW5fYWJzb2x1dGVfcGFpcndpc2VfZGlmZmVyZW5jZSgKICAgICAgICAgICAgICAgIG1hcmdpbmFsX21lYW4KICAgICAgICAgICAgICApLAogICAgICAgICAgICBuX2xldmVscyA9IG4oKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICAgICAgKSAlPiUKICAgICAgICAgIG11dGF0ZSgKICAgICAgICAgICAgY3VlX2ZhbWlseSA9IHVubmFtZSgKICAgICAgICAgICAgICBwcmVwYXJlZCRjdWVfbWFwW2F0dHJpYnV0ZV0KICAgICAgICAgICAgKSwKICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5ID0gMSAvIHBhcnR5X24sCiAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UgLwogICAgICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5CiAgICAgICAgICApCgogICAgICAgIGN1ZV90YWJsZV9sb25nIDwtIGF0dHJpYnV0ZV90YWJsZSAlPiUKICAgICAgICAgIGdyb3VwX2J5KAogICAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgICBjdWVfZmFtaWx5CiAgICAgICAgICApICU+JQogICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlID0gbWVhbigKICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICApLAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0gbWVhbigKICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICApLAogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICAgICApCgogICAgICAgIHBhcnR5X3RhYmxlIDwtIGN1ZV90YWJsZV9sb25nICU+JQogICAgICAgICAgZmlsdGVyKAogICAgICAgICAgICBjdWVfZmFtaWx5ID09ICJwYXJ0eSIKICAgICAgICAgICkgJT4lCiAgICAgICAgICB0cmFuc211dGUoCiAgICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQKICAgICAgICAgICkKCiAgICAgICAgZWNvbm9taWNfdGFibGUgPC0gY3VlX3RhYmxlX2xvbmcgJT4lCiAgICAgICAgICBmaWx0ZXIoCiAgICAgICAgICAgIGN1ZV9mYW1pbHkgPT0gImVjb25vbWljIgogICAgICAgICAgKSAlPiUKICAgICAgICAgIHRyYW5zbXV0ZSgKICAgICAgICAgICAgcGFydHlfbiwKICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSA9CiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZAogICAgICAgICAgKQoKICAgICAgICBjdWVfdGFibGUgPC0gZnVsbF9qb2luKAogICAgICAgICAgcGFydHlfdGFibGUsCiAgICAgICAgICBlY29ub21pY190YWJsZSwKICAgICAgICAgIGJ5ID0gInBhcnR5X24iCiAgICAgICAgKSAlPiUKICAgICAgICAgIG11dGF0ZSgKICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5ID0gMSAvIHBhcnR5X24sCgogICAgICAgICAgICB0b3RhbF9pbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlICsKICAgICAgICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlLAoKICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCArCiAgICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKCiAgICAgICAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSA9IGlmX2Vsc2UoCiAgICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZSA+IDAsCiAgICAgICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSAvCiAgICAgICAgICAgICAgICB0b3RhbF9pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgICAgIE5BX3JlYWxfCiAgICAgICAgICAgICksCgogICAgICAgICAgICByZWxhdGl2ZV9lY29ub21pY193ZWlnaHRfcGFpcndpc2UgPQogICAgICAgICAgICAgIDEgLSByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UsCgogICAgICAgICAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2VfYWRqdXN0ZWQgPSBpZl9lbHNlKAogICAgICAgICAgICAgIHRvdGFsX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPiAwLAogICAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgLwogICAgICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKICAgICAgICAgICAgICBOQV9yZWFsXwogICAgICAgICAgICApLAoKICAgICAgICAgICAgcmVsYXRpdmVfZWNvbm9taWNfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAgICAgICAxIC0gcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkLAoKICAgICAgICAgICAgYWRqdXN0bWVudF9pZGVudGl0eV9kaWZmZXJlbmNlID0KICAgICAgICAgICAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2VfYWRqdXN0ZWQgLQogICAgICAgICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlCiAgICAgICAgICApCgogICAgICAgIGlmICgKICAgICAgICAgIGFueSgKICAgICAgICAgICAgYWJzKGN1ZV90YWJsZSRhZGp1c3RtZW50X2lkZW50aXR5X2RpZmZlcmVuY2UpID4gMWUtMTAsCiAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgKQogICAgICAgICkgewogICAgICAgICAgc3RvcCgiQ2hlY2sgcmVsYXRpdmUgd2VpZ2h0IikKICAgICAgICB9CgogICAgICAgIGxpc3QoCiAgICAgICAgICBtYXJnaW5hbF9tZWFucyA9IG1tX3RhYmxlLAogICAgICAgICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPSBhdHRyaWJ1dGVfdGFibGUsCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSA9IGN1ZV90YWJsZQogICAgICAgICkKICAgICAgfQogICAgKQoKICAgIGxpc3QoCiAgICAgIG1hcmdpbmFsX21lYW5zID0gYmluZF9yb3dzKAogICAgICAgIGxhcHBseSgKICAgICAgICAgIGNvbmRpdGlvbl9yZXN1bHRzLAogICAgICAgICAgZnVuY3Rpb24oeCkgeCRtYXJnaW5hbF9tZWFucwogICAgICAgICkKICAgICAgKSwKICAgICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPSBiaW5kX3Jvd3MoCiAgICAgICAgbGFwcGx5KAogICAgICAgICAgY29uZGl0aW9uX3Jlc3VsdHMsCiAgICAgICAgICBmdW5jdGlvbih4KSB4JGF0dHJpYnV0ZV9pbXBvcnRhbmNlCiAgICAgICAgKQogICAgICApLAogICAgICBjdWVfaW1wb3J0YW5jZSA9IGJpbmRfcm93cygKICAgICAgICBsYXBwbHkoCiAgICAgICAgICBjb25kaXRpb25fcmVzdWx0cywKICAgICAgICAgIGZ1bmN0aW9uKHgpIHgkY3VlX2ltcG9ydGFuY2UKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgICAgYXJyYW5nZShwYXJ0eV9uKQogICAgKQogIH0KCiAgZXN0aW1hdGVfcmVsYXRpdmVfY3VlX3Nsb3BlcyA8LSBmdW5jdGlvbihjdWVfaW1wb3J0YW5jZSkgewogICAgY3VlX2ltcG9ydGFuY2UgPC0gY3VlX2ltcG9ydGFuY2UgJT4lCiAgICAgIGFycmFuZ2UocGFydHlfbikKCiAgICBpZiAoIWlkZW50aWNhbChjdWVfaW1wb3J0YW5jZSRwYXJ0eV9uLCAyOjUpKSB7CiAgICAgIHN0b3AoIkNoZWNrIHJlbGF0aXZlIHdlaWdodCIpCiAgICB9CgogICAgeCA8LSBjdWVfaW1wb3J0YW5jZSRwYXJ0eV9uCgogICAgYygKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICB4CiAgICAgICAgKQogICAgKQogIH0KCiAgcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAgPC0gZnVuY3Rpb24oCiAgICAgIHByZXBhcmVkLAogICAgICBCLAogICAgICBzZWVkLAogICAgICBwcm9ncmVzc19ldmVyeSA9IDEwMAogICkgewogICAgc2V0LnNlZWQoc2VlZCkKCiAgICBjb25kaXRpb25fcmVzdWx0cyA8LSB2ZWN0b3IoCiAgICAgICJsaXN0IiwKICAgICAgQgogICAgKQoKICAgIHNsb3BlX25hbWVzIDwtIGMoCiAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiLAogICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiwKICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICkKCiAgICBzbG9wZV9tYXRyaXggPC0gbWF0cml4KAogICAgICBOQV9yZWFsXywKICAgICAgbnJvdyA9IEIsCiAgICAgIG5jb2wgPSBsZW5ndGgoc2xvcGVfbmFtZXMpLAogICAgICBkaW1uYW1lcyA9IGxpc3QoCiAgICAgICAgTlVMTCwKICAgICAgICBzbG9wZV9uYW1lcwogICAgICApCiAgICApCgogICAgZm9yIChiIGluIHNlcV9sZW4oQikpIHsKICAgICAgY2x1c3Rlcl93ZWlnaHRzIDwtIGxhcHBseSgKICAgICAgICBwcmVwYXJlZCRjb25kaXRpb25zLAogICAgICAgIGZ1bmN0aW9uKG9iamVjdCkgewogICAgICAgICAgbl9pZHMgPC0gbGVuZ3RoKG9iamVjdCRpZHMpCgogICAgICAgICAgc2FtcGxlZF9wb3NpdGlvbnMgPC0gc2FtcGxlLmludCgKICAgICAgICAgICAgbiA9IG5faWRzLAogICAgICAgICAgICBzaXplID0gbl9pZHMsCiAgICAgICAgICAgIHJlcGxhY2UgPSBUUlVFCiAgICAgICAgICApCgogICAgICAgICAgdGFidWxhdGUoCiAgICAgICAgICAgIHNhbXBsZWRfcG9zaXRpb25zLAogICAgICAgICAgICBuYmlucyA9IG5faWRzCiAgICAgICAgICApCiAgICAgICAgfQogICAgICApCgogICAgICBib290c3RyYXBfZXN0aW1hdGVzIDwtIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzKAogICAgICAgIHByZXBhcmVkID0gcHJlcGFyZWQsCiAgICAgICAgY2x1c3Rlcl93ZWlnaHRzID0gY2x1c3Rlcl93ZWlnaHRzCiAgICAgICkKCiAgICAgIGNvbmRpdGlvbl9yZXN1bHRzW1tiXV0gPC0KICAgICAgICBib290c3RyYXBfZXN0aW1hdGVzJGN1ZV9pbXBvcnRhbmNlICU+JQogICAgICAgIHNlbGVjdCgKICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlCiAgICAgICAgKSAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBib290c3RyYXBfcmVwbGljYXRpb24gPSBiLAogICAgICAgICAgLmJlZm9yZSA9IDEKICAgICAgICApCgogICAgICBzbG9wZV9tYXRyaXhbYiwgXSA8LSBlc3RpbWF0ZV9yZWxhdGl2ZV9jdWVfc2xvcGVzKAogICAgICAgIGJvb3RzdHJhcF9lc3RpbWF0ZXMkY3VlX2ltcG9ydGFuY2UKICAgICAgKQoKICAgICAgaWYgKAogICAgICAgIHByb2dyZXNzX2V2ZXJ5ID4gMCAmJgogICAgICAgIChiICUlIHByb2dyZXNzX2V2ZXJ5ID09IDAgfHwgYiA9PSBCKQogICAgICApIHsKICAgICAgICBtZXNzYWdlKCJCb290c3RyYXA6ICIsIGIsICIvIiwgQikKICAgICAgfQogICAgfQoKICAgIGxpc3QoCiAgICAgIGNvbmRpdGlvbl9lc3RpbWF0ZXMgPSBiaW5kX3Jvd3MoCiAgICAgICAgY29uZGl0aW9uX3Jlc3VsdHMKICAgICAgKSwKICAgICAgc2xvcGVzID0gYXNfdGliYmxlKAogICAgICAgIHNsb3BlX21hdHJpeAogICAgICApICU+JQogICAgICAgIG11dGF0ZSgKICAgICAgICAgIGJvb3RzdHJhcF9yZXBsaWNhdGlvbiA9IHJvd19udW1iZXIoKSwKICAgICAgICAgIC5iZWZvcmUgPSAxCiAgICAgICAgKQogICAgKQogIH0KCiAgc3VtbWFyaXNlX2NvbmRpdGlvbl9pbnRlcnZhbHMgPC0gZnVuY3Rpb24oCiAgICAgIG9ic2VydmVkX2N1ZV9pbXBvcnRhbmNlLAogICAgICBib290c3RyYXBfY29uZGl0aW9uX3Jlc3VsdHMKICApIHsKICAgIHN0YXRpc3RpY3MgPC0gYygKICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UiLAogICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIgogICAgKQoKICAgIG9ic2VydmVkX2xvbmcgPC0gb2JzZXJ2ZWRfY3VlX2ltcG9ydGFuY2UgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBwYXJ0eV9uLAogICAgICAgIGFsbF9vZihzdGF0aXN0aWNzKQogICAgICApICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihzdGF0aXN0aWNzKSwKICAgICAgICBuYW1lc190byA9ICJzdGF0aXN0aWMiLAogICAgICAgIHZhbHVlc190byA9ICJlc3RpbWF0ZSIKICAgICAgKQoKICAgIGJvb3RzdHJhcF9sb25nIDwtIGJvb3RzdHJhcF9jb25kaXRpb25fcmVzdWx0cyAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2Yoc3RhdGlzdGljcyksCiAgICAgICAgbmFtZXNfdG8gPSAic3RhdGlzdGljIiwKICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiCiAgICAgICkgJT4lCiAgICAgIGdyb3VwX2J5KAogICAgICAgIHBhcnR5X24sCiAgICAgICAgc3RhdGlzdGljCiAgICAgICkgJT4lCiAgICAgIHN1bW1hcmlzZSgKICAgICAgICBjb25mX2xvdyA9IHNhZmVfcXVhbnRpbGUoCiAgICAgICAgICB2YWx1ZSwKICAgICAgICAgIDAuMDI1CiAgICAgICAgKSwKICAgICAgICBjb25mX2hpZ2ggPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgdmFsdWUsCiAgICAgICAgICAwLjk3NQogICAgICAgICksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApCgogICAgb2JzZXJ2ZWRfbG9uZyAlPiUKICAgICAgbGVmdF9qb2luKAogICAgICAgIGJvb3RzdHJhcF9sb25nLAogICAgICAgIGJ5ID0gYygKICAgICAgICAgICJwYXJ0eV9uIiwKICAgICAgICAgICJzdGF0aXN0aWMiCiAgICAgICAgKQogICAgICApCiAgfQoKICBzdW1tYXJpc2Vfc2xvcGVfaW5mZXJlbmNlIDwtIGZ1bmN0aW9uKAogICAgICBvYnNlcnZlZF9zbG9wZXMsCiAgICAgIGJvb3RzdHJhcF9zbG9wZXMKICApIHsKICAgIHN0YXRpc3RpY19uYW1lcyA8LSBuYW1lcyhvYnNlcnZlZF9zbG9wZXMpCgogICAgbWFwX2RmcigKICAgICAgc3RhdGlzdGljX25hbWVzLAogICAgICBmdW5jdGlvbihzdGF0aXN0aWNfbmFtZSkgewogICAgICAgIGJvb3RzdHJhcF92YWx1ZXMgPC0gYm9vdHN0cmFwX3Nsb3Blc1tbc3RhdGlzdGljX25hbWVdXQogICAgICAgIGJvb3RzdHJhcF92YWx1ZXMgPC0gYm9vdHN0cmFwX3ZhbHVlc1sKICAgICAgICAgIGlzLmZpbml0ZShib290c3RyYXBfdmFsdWVzKQogICAgICAgIF0KCiAgICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uIDwtIGNhc2Vfd2hlbigKICAgICAgICAgIHN0YXRpc3RpY19uYW1lID09CiAgICAgICAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiB+ICJuZWdhdGl2ZSIsCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSAlaW4lIGMoCiAgICAgICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlIiwKICAgICAgICAgICAgInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIsCiAgICAgICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIgogICAgICAgICAgKSB+ICJwb3NpdGl2ZSIsCiAgICAgICAgICBUUlVFIH4gIm5vbmUiCiAgICAgICAgKQoKICAgICAgICBhbmFseXNpc19yb2xlIDwtIGNhc2Vfd2hlbigKICAgICAgICAgIHN0YXRpc3RpY19uYW1lICVpbiUgYygKICAgICAgICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAgICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICAgICAgICkgfiAiZXhwbG9yYXRvcnlfY2hvaWNlX3NldF9hZGp1c3RlZCIsCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIiB+CiAgICAgICAgICAgICJkZXJpdmVkX3JlbGF0aXZlX3NoYXJlIiwKICAgICAgICAgIFRSVUUgfiAibWFudXNjcmlwdF9wcmltYXJ5X3VuYWRqdXN0ZWQiCiAgICAgICAgKQoKICAgICAgICBlc3RpbWF0ZSA8LSB1bm5hbWUoCiAgICAgICAgICBvYnNlcnZlZF9zbG9wZXNbW3N0YXRpc3RpY19uYW1lXV0KICAgICAgICApCgogICAgICAgIHRpYmJsZSgKICAgICAgICAgIHN0dWR5ID0gIlN0dWR5IDEiLAogICAgICAgICAgc3RhdGlzdGljID0gc3RhdGlzdGljX25hbWUsCiAgICAgICAgICBlc3RpbWF0ZSA9IGVzdGltYXRlLAogICAgICAgICAgY29uZl9sb3cgPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgICBib290c3RyYXBfdmFsdWVzLAogICAgICAgICAgICAwLjAyNQogICAgICAgICAgKSwKICAgICAgICAgIGNvbmZfaGlnaCA9IHNhZmVfcXVhbnRpbGUoCiAgICAgICAgICAgIGJvb3RzdHJhcF92YWx1ZXMsCiAgICAgICAgICAgIDAuOTc1CiAgICAgICAgICApLAogICAgICAgICAgcF92YWx1ZV90d29fc2lkZWQgPQogICAgICAgICAgICBib290c3RyYXBfdHdvX3NpZGVkX3AoCiAgICAgICAgICAgICAgYm9vdHN0cmFwX3ZhbHVlcwogICAgICAgICAgICApLAogICAgICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uID0gZXhwZWN0ZWRfZGlyZWN0aW9uLAogICAgICAgICAgYW5hbHlzaXNfcm9sZSA9IGFuYWx5c2lzX3JvbGUsCiAgICAgICAgICBlc3RpbWF0ZV9pbl9leHBlY3RlZF9kaXJlY3Rpb24gPSBjYXNlX3doZW4oCiAgICAgICAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA9PSAicG9zaXRpdmUiIH4gZXN0aW1hdGUgPiAwLAogICAgICAgICAgICBleHBlY3RlZF9kaXJlY3Rpb24gPT0gIm5lZ2F0aXZlIiB+IGVzdGltYXRlIDwgMCwKICAgICAgICAgICAgVFJVRSB+IE5BCiAgICAgICAgICApCiAgICAgICAgKQogICAgICB9CiAgICApCiAgfQoKICByZWxhdGl2ZV9jdWVfcHJlcGFyZWQgPC0gcHJlcGFyZV9yZWxhdGl2ZV9jdWVfYW5hbHlzaXMoCiAgICBkYXRhID0gY29uam9pbnRfYWxsX20sCiAgICBjdWVfbWFwID0gcmVsYXRpdmVfY3VlX21hcAogICkKCiAgcmVsYXRpdmVfY3VlX29ic2VydmVkIDwtIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzKAogICAgcHJlcGFyZWQgPSByZWxhdGl2ZV9jdWVfcHJlcGFyZWQKICApCgogIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZF9zbG9wZXMgPC0gZXN0aW1hdGVfcmVsYXRpdmVfY3VlX3Nsb3BlcygKICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZQogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRtYXJnaW5hbF9tZWFucywKICAgICJzdHVkeTFfcmVsYXRpdmVfY3VlX21hcmdpbmFsX21lYW5zLmNzdiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkYXR0cmlidXRlX2ltcG9ydGFuY2UsCiAgICAic3R1ZHkxX3JlbGF0aXZlX2N1ZV9hdHRyaWJ1dGVfaW1wb3J0YW5jZS5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJGN1ZV9pbXBvcnRhbmNlLAogICAgInN0dWR5MV9yZWxhdGl2ZV9jdWVfaW1wb3J0YW5jZV9hbmRfd2VpZ2h0LmNzdiIKICApCgogIHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSA8LSBmaWxlLnBhdGgoCiAgICBvdXRwdXRfZGlyLAogICAgcGFzdGUwKAogICAgICAic3R1ZHkxX3JlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwXyIsCiAgICAgIHVuaWZpZWRfY29uZmlnJGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uLAogICAgICAiX0IiLAogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgICIuY3N2IgogICAgKQogICkKCiAgcmVsYXRpdmVfc2xvcGVfYm9vdHN0cmFwX2ZpbGUgPC0gZmlsZS5wYXRoKAogICAgb3V0cHV0X2RpciwKICAgIHBhc3RlMCgKICAgICAgInN0dWR5MV9yZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwXyIsCiAgICAgIHVuaWZpZWRfY29uZmlnJGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uLAogICAgICAiX0IiLAogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgICIuY3N2IgogICAgKQogICkKCiAgdXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCA8LQogICAgIXJlcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAgJiYKICAgIGZpbGUuZXhpc3RzKHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSkgJiYKICAgIGZpbGUuZXhpc3RzKHJlbGF0aXZlX3Nsb3BlX2Jvb3RzdHJhcF9maWxlKQoKICBpZiAodXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCkgewogICAgbWVzc2FnZSgiQm9vdHN0cmFwIGNhY2hlIikKCiAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcCA8LSByZWFkcjo6cmVhZF9jc3YoCiAgICAgIHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSwKICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRQogICAgKQoKICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9ib290c3RyYXAgPC0gcmVhZHI6OnJlYWRfY3N2KAogICAgICByZWxhdGl2ZV9zbG9wZV9ib290c3RyYXBfZmlsZSwKICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRQogICAgKQoKICAgIHNhdmVkX0JfY29uZGl0aW9uIDwtIG5fZGlzdGluY3QoCiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwJGJvb3RzdHJhcF9yZXBsaWNhdGlvbgogICAgKQogICAgc2F2ZWRfQl9zbG9wZSA8LSBuX2Rpc3RpbmN0KAogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwJGJvb3RzdHJhcF9yZXBsaWNhdGlvbgogICAgKQoKICAgIGlmICgKICAgICAgc2F2ZWRfQl9jb25kaXRpb24gIT0gcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CIHx8CiAgICAgIHNhdmVkX0Jfc2xvcGUgIT0gcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CCiAgICApIHsKICAgICAgbWVzc2FnZSgiQm9vdHN0cmFwIGNhY2hlIikKICAgICAgdXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCA8LSBGQUxTRQogICAgfQogIH0KCiAgaWYgKCF1c2Vfc2F2ZWRfcmVsYXRpdmVfYm9vdHN0cmFwKSB7CiAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwIDwtIHJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwKAogICAgICBwcmVwYXJlZCA9IHJlbGF0aXZlX2N1ZV9wcmVwYXJlZCwKICAgICAgQiA9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQiwKICAgICAgc2VlZCA9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfc2VlZCwKICAgICAgcHJvZ3Jlc3NfZXZlcnkgPSByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3Byb2dyZXNzX2V2ZXJ5CiAgICApCgogICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9ib290c3RyYXAgPC0KICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCRjb25kaXRpb25fZXN0aW1hdGVzCgogICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcCA8LQogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwJHNsb3BlcwoKICAgIHJlYWRyOjp3cml0ZV9jc3YoCiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwLAogICAgICByZWxhdGl2ZV9jb25kaXRpb25fYm9vdHN0cmFwX2ZpbGUKICAgICkKCiAgICByZWFkcjo6d3JpdGVfY3N2KAogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwLAogICAgICByZWxhdGl2ZV9zbG9wZV9ib290c3RyYXBfZmlsZQogICAgKQogIH0KCiAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgPC0gc3VtbWFyaXNlX2NvbmRpdGlvbl9pbnRlcnZhbHMoCiAgICBvYnNlcnZlZF9jdWVfaW1wb3J0YW5jZSA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgIGJvb3RzdHJhcF9jb25kaXRpb25fcmVzdWx0cyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwCiAgKQoKICByZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlIDwtIHN1bW1hcmlzZV9zbG9wZV9pbmZlcmVuY2UoCiAgICBvYnNlcnZlZF9zbG9wZXMgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWRfc2xvcGVzLAogICAgYm9vdHN0cmFwX3Nsb3BlcyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9ib290c3RyYXAKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscywKICAgICJzdHVkeTFfcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UsCiAgICAic3R1ZHkxX3JlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UuY3N2IgogICkKCiAgcmVsYXRpdmVfY3VlX3ByaW1hcnlfcmVzdWx0IDwtIHJlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyA9PQogICAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiCiAgICApCgogIGNhdCgiXG5TdHVkeSAx77ya55u45a++5q+U6YeN44Gu57ea5b2i5YK+5ZCRXG4iKQogIHByaW50KHJlbGF0aXZlX2N1ZV9wcmltYXJ5X3Jlc3VsdCkKCgogIHJlbGF0aXZlX3hfb2Zmc2V0IDwtIDAuMDc1CgogIHJlbGF0aXZlX3BhbmVsX2FfZGF0YSA8LSByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscyAlPiUKICAgIGZpbHRlcigKICAgICAgc3RhdGlzdGljICVpbiUgYygKICAgICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UiCiAgICAgICkKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGN1ZV9mYW1pbHkgPSByZWNvZGUoCiAgICAgICAgc3RhdGlzdGljLAogICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPSAi5pS/5YWa5omL44GM44GL44KKIiwKICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlID0gIue1jOa4iOaJi+OBjOOBi+OCiiIKICAgICAgKSwKICAgICAgY3VlX2ZhbWlseSA9IGZhY3RvcigKICAgICAgICBjdWVfZmFtaWx5LAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAi5pS/5YWa5omL44GM44GL44KKIiwKICAgICAgICAgICLntYzmuIjmiYvjgYzjgYvjgooiCiAgICAgICAgKQogICAgICApLAogICAgICB4X3Bsb3QgPSBjYXNlX3doZW4oCiAgICAgICAgY3VlX2ZhbWlseSA9PSAi5pS/5YWa5omL44GM44GL44KKIiB+CiAgICAgICAgICBwYXJ0eV9uICsgcmVsYXRpdmVfeF9vZmZzZXQsCiAgICAgICAgY3VlX2ZhbWlseSA9PSAi57WM5riI5omL44GM44GL44KKIiB+CiAgICAgICAgICBwYXJ0eV9uIC0gcmVsYXRpdmVfeF9vZmZzZXQsCiAgICAgICAgVFJVRSB+IGFzLm51bWVyaWMocGFydHlfbikKICAgICAgKSwKICAgICAgdmFsdWVfbGFiZWwgPSBzcHJpbnRmKAogICAgICAgICIlLjNmIiwKICAgICAgICBlc3RpbWF0ZQogICAgICApCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2JfZGF0YSA8LSByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscyAlPiUKICAgIGZpbHRlcigKICAgICAgc3RhdGlzdGljID09CiAgICAgICAgInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIHZhbHVlX2xhYmVsID0gc3ByaW50ZigKICAgICAgICAiJS4xZiUlIiwKICAgICAgICAxMDAgKiBlc3RpbWF0ZQogICAgICApCiAgICApCgogIHJlbGF0aXZlX2FkanVzdGVkX2xhYmVsX21hcCA8LSByZWxhdGl2ZV9wYW5lbF9hX2RhdGEgJT4lCiAgICBkaXN0aW5jdCgKICAgICAgc3RhdGlzdGljLAogICAgICBjdWVfZmFtaWx5CiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBzdGF0aXN0aWMgPSBwYXN0ZTAoCiAgICAgICAgc3RhdGlzdGljLAogICAgICAgICJfYWRqdXN0ZWQiCiAgICAgICksCiAgICAgIGN1ZV9mYW1pbHkgPSBhcy5jaGFyYWN0ZXIoCiAgICAgICAgY3VlX2ZhbWlseQogICAgICApCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEgPC0gcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyAlaW4lIGMoCiAgICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIgogICAgICApCiAgICApICU+JQogICAgbGVmdF9qb2luKAogICAgICByZWxhdGl2ZV9hZGp1c3RlZF9sYWJlbF9tYXAsCiAgICAgIGJ5ID0gInN0YXRpc3RpYyIKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGN1ZV9mYW1pbHkgPSBmYWN0b3IoCiAgICAgICAgY3VlX2ZhbWlseSwKICAgICAgICBsZXZlbHMgPSBsZXZlbHMoCiAgICAgICAgICByZWxhdGl2ZV9wYW5lbF9hX2RhdGEkY3VlX2ZhbWlseQogICAgICAgICkKICAgICAgKSwKICAgICAgeF9wbG90ID0gaWZfZWxzZSgKICAgICAgICBhcy5pbnRlZ2VyKGN1ZV9mYW1pbHkpID09IDFMLAogICAgICAgIHBhcnR5X24gKyByZWxhdGl2ZV94X29mZnNldCwKICAgICAgICBwYXJ0eV9uIC0gcmVsYXRpdmVfeF9vZmZzZXQKICAgICAgKSwKICAgICAgdmFsdWVfbGFiZWwgPSBzcHJpbnRmKAogICAgICAgICIlLjFmJSUiLAogICAgICAgIDEwMCAqIGVzdGltYXRlCiAgICAgICkKICAgICkKCiAgcmVsYXRpdmVfY29uZGl0aW9uX3N1ZmZpeCA8LSBpZiAoCiAgICAi5pS/5YWa5ZCN5omL44GM44GL44KKIiAlaW4lCiAgICAgIGxldmVscyhyZWxhdGl2ZV9wYW5lbF9hX2RhdGEkY3VlX2ZhbWlseSkKICApIHsKICAgICLpgbjmip7ogqIiCiAgfSBlbHNlIHsKICAgICLmlL/lhZoiCiAgfQoKICByZWxhdGl2ZV9jb25kaXRpb25fYXhpc190aXRsZSA8LSBpZiAoCiAgICByZWxhdGl2ZV9jb25kaXRpb25fc3VmZml4ID09ICLpgbjmip7ogqIiCiAgKSB7CiAgICAi5pS/5rK757WM5riI54q25rOB44Gu6YG45oqe6IKi5pWwIgogIH0gZWxzZSB7CiAgICAi5pS/5YWa6YG45oqe6IKi5pWwIgogIH0KCiAgcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5IDwtIGlmICgKICAgIC5QbGF0Zm9ybSRPUy50eXBlID09ICJ3aW5kb3dzIgogICkgewogICAgIll1IEdvdGhpYyIKICB9IGVsc2UgewogICAgInNhbnMiCiAgfQoKICByZWxhdGl2ZV90aGVtZV9qYXBhbmVzZV9idyA8LSB0aGVtZV9idygKICAgIGJhc2Vfc2l6ZSA9IDEyLAogICAgYmFzZV9mYW1pbHkgPSByZWxhdGl2ZV9maWd1cmVfZm9udF9mYW1pbHkKICApICsKICAgIHRoZW1lKAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKAogICAgICAgIGxpbmV3aWR0aCA9IDAuMzAsCiAgICAgICAgY29sb3IgPSAiZ3JleTg4IgogICAgICApLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgbGluZXdpZHRoID0gMC42NSwKICAgICAgICBjb2xvciA9ICJibGFjayIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGNvbG9yID0gImJsYWNrIgogICAgICApLAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGNvbG9yID0gImJsYWNrIgogICAgICApLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSAxMi41LAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgaGp1c3QgPSAwCiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDkuNSwKICAgICAgICBoanVzdCA9IDAsCiAgICAgICAgbWFyZ2luID0gbWFyZ2luKAogICAgICAgICAgYiA9IDgKICAgICAgICApCiAgICAgICksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLAogICAgICBsZWdlbmQua2V5LndpZHRoID0gZ3JpZDo6dW5pdCgKICAgICAgICAxLjI1LAogICAgICAgICJjbSIKICAgICAgKSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oCiAgICAgICAgOCwKICAgICAgICAxMCwKICAgICAgICA4LAogICAgICAgIDgKICAgICAgKQogICAgKQoKICByZWxhdGl2ZV9wYW5lbF9hIDwtIGdncGxvdCgKICAgIHJlbGF0aXZlX3BhbmVsX2FfZGF0YSwKICAgIGFlcygKICAgICAgeCA9IHhfcGxvdCwKICAgICAgeSA9IGVzdGltYXRlLAogICAgICBncm91cCA9IGN1ZV9mYW1pbHksCiAgICAgIGxpbmV0eXBlID0gY3VlX2ZhbWlseQogICAgKQogICkgKwogICAgZ2VvbV9saW5lKAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKAogICAgICAgIHltaW4gPSBjb25mX2xvdywKICAgICAgICB5bWF4ID0gY29uZl9oaWdoCiAgICAgICksCiAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xhYmVsKAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSB2YWx1ZV9sYWJlbAogICAgICApLAogICAgICBzaXplID0gMy41NSwKICAgICAgZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICBsYWJlbC5zaXplID0gMCwKICAgICAgbGFiZWwucGFkZGluZyA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMC4xMiwKICAgICAgICAibGluZXMiCiAgICAgICksCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICLmlL/lhZrmiYvjgYzjgYvjgooiID0gInNvbGlkIiwKICAgICAgICAi57WM5riI5omL44GM44GL44KKIiA9ICJkYXNoZWQiCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBicmVha3MgPSAyOjUsCiAgICAgIGxhYmVscyA9IHBhc3RlMCgKICAgICAgICAyOjUsCiAgICAgICAgIuaUv+WFmiIKICAgICAgKSwKICAgICAgbGltaXRzID0gYygKICAgICAgICAxLjcyLAogICAgICAgIDUuMjgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGxhYmVsX251bWJlcigKICAgICAgICBhY2N1cmFjeSA9IDAuMDA1CiAgICAgICksCiAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbigKICAgICAgICBtdWx0ID0gYygKICAgICAgICAgIDAuMDcsCiAgICAgICAgICAwLjEwCiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkHvvJrkuKHmiYvjgYzjgYvjgorjga7ntbblr77nmoTph43opoHluqYiLAogICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICB4ID0gIuaUv+WFmumBuOaKnuiCouaVsCIsCiAgICAgIHkgPSAi5omL44GM44GL44KK6YeN6KaB5bqmIiwKICAgICAgbGluZXR5cGUgPSBOVUxMCiAgICApICsKICAgIGd1aWRlcygKICAgICAgbGluZXR5cGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIGxpbmV3aWR0aCA9IDAuOTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncKCiAgcmVsYXRpdmVfYWRqdXN0ZWRfbGluZXR5cGVzIDwtIHNldE5hbWVzKAogICAgYygKICAgICAgInNvbGlkIiwKICAgICAgImRhc2hlZCIKICAgICksCiAgICBsZXZlbHMoCiAgICAgIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEkY3VlX2ZhbWlseQogICAgKQogICkKCiAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWQgPC0gZ2dwbG90KAogICAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWRfZGF0YSwKICAgIGFlcygKICAgICAgeCA9IHhfcGxvdCwKICAgICAgeSA9IGVzdGltYXRlLAogICAgICBncm91cCA9IGN1ZV9mYW1pbHksCiAgICAgIGxpbmV0eXBlID0gY3VlX2ZhbWlseQogICAgKQogICkgKwogICAgZ2VvbV9saW5lKAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKAogICAgICAgIHltaW4gPSBjb25mX2xvdywKICAgICAgICB5bWF4ID0gY29uZl9oaWdoCiAgICAgICksCiAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xhYmVsKAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSB2YWx1ZV9sYWJlbAogICAgICApLAogICAgICBzaXplID0gMy41NSwKICAgICAgZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICBsYWJlbC5zaXplID0gMCwKICAgICAgbGFiZWwucGFkZGluZyA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMC4xMiwKICAgICAgICAibGluZXMiCiAgICAgICksCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICB2YWx1ZXMgPSByZWxhdGl2ZV9hZGp1c3RlZF9saW5ldHlwZXMKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBicmVha3MgPSAyOjUsCiAgICAgIGxhYmVscyA9IHBhc3RlMCgKICAgICAgICAyOjUsCiAgICAgICAgcmVsYXRpdmVfY29uZGl0aW9uX3N1ZmZpeAogICAgICApLAogICAgICBsaW1pdHMgPSBjKAogICAgICAgIDEuNzIsCiAgICAgICAgNS4yOAogICAgICApCiAgICApICsKICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgbGFiZWxzID0gbGFiZWxfcGVyY2VudCgKICAgICAgICBhY2N1cmFjeSA9IDEKICAgICAgKSwKICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKAogICAgICAgIG11bHQgPSBjKAogICAgICAgICAgMC4wNywKICAgICAgICAgIDAuMTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiQe+8mumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6piIsCiAgICAgIHN1YnRpdGxlID0KICAgICAgICAi5pyq6Kq/5pW06YeN6KaB5bqmIMO3IOW5s+Wdh+mBuOaKnueiuueOh++8iDHvvI/pgbjmip7ogqLmlbDvvIkiLAogICAgICB4ID0gcmVsYXRpdmVfY29uZGl0aW9uX2F4aXNfdGl0bGUsCiAgICAgIHkgPSAi5bmz5Z2H6YG45oqe56K6546H44Gr5a++44GZ44KL5rC05rqW6ZaT5beuIiwKICAgICAgbGluZXR5cGUgPSBOVUxMCiAgICApICsKICAgIGd1aWRlcygKICAgICAgbGluZXR5cGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIGxpbmV3aWR0aCA9IDAuOTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncKCiAgcmVsYXRpdmVfYl9yYW5nZSA8LSByYW5nZSgKICAgIGMoCiAgICAgIHJlbGF0aXZlX3BhbmVsX2JfZGF0YSRjb25mX2xvdywKICAgICAgcmVsYXRpdmVfcGFuZWxfYl9kYXRhJGNvbmZfaGlnaCwKICAgICAgMC41CiAgICApLAogICAgbmEucm0gPSBUUlVFCiAgKQoKICByZWxhdGl2ZV9iX3BhZGRpbmcgPC0gbWF4KAogICAgMC4wMjUsCiAgICAwLjEwICogZGlmZihyZWxhdGl2ZV9iX3JhbmdlKQogICkKCiAgcmVsYXRpdmVfYl9sb3dlciA8LSBtYXgoCiAgICAwLAogICAgZmxvb3IoCiAgICAgIDIwICoKICAgICAgICAocmVsYXRpdmVfYl9yYW5nZVsxXSAtIHJlbGF0aXZlX2JfcGFkZGluZykKICAgICkgLyAyMAogICkKCiAgcmVsYXRpdmVfYl91cHBlciA8LSBtaW4oCiAgICAxLAogICAgY2VpbGluZygKICAgICAgMjAgKgogICAgICAgIChyZWxhdGl2ZV9iX3JhbmdlWzJdICsgcmVsYXRpdmVfYl9wYWRkaW5nKQogICAgKSAvIDIwCiAgKQoKICBpZiAocmVsYXRpdmVfYl9sb3dlciA+PSByZWxhdGl2ZV9iX3VwcGVyKSB7CiAgICByZWxhdGl2ZV9iX2xvd2VyIDwtIG1heCgKICAgICAgMCwKICAgICAgcmVsYXRpdmVfYl9sb3dlciAtIDAuMDUKICAgICkKICAgIHJlbGF0aXZlX2JfdXBwZXIgPC0gbWluKAogICAgICAxLAogICAgICByZWxhdGl2ZV9iX3VwcGVyICsgMC4wNQogICAgKQogIH0KCiAgcmVsYXRpdmVfcGFuZWxfYiA8LSBnZ3Bsb3QoCiAgICByZWxhdGl2ZV9wYW5lbF9iX2RhdGEsCiAgICBhZXMoCiAgICAgIHggPSBwYXJ0eV9uLAogICAgICB5ID0gZXN0aW1hdGUKICAgICkKICApICsKICAgIGdlb21faGxpbmUoCiAgICAgIHlpbnRlcmNlcHQgPSAwLjUsCiAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xpbmUoCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyKAogICAgICBhZXMoCiAgICAgICAgeW1pbiA9IGNvbmZfbG93LAogICAgICAgIHltYXggPSBjb25mX2hpZ2gKICAgICAgKSwKICAgICAgd2lkdGggPSAwLjA3NSwKICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fbGFiZWwoCiAgICAgIGFlcygKICAgICAgICBsYWJlbCA9IHZhbHVlX2xhYmVsCiAgICAgICksCiAgICAgIHNpemUgPSAzLjU1LAogICAgICBmYW1pbHkgPSByZWxhdGl2ZV9maWd1cmVfZm9udF9mYW1pbHksCiAgICAgIGxhYmVsLnNpemUgPSAwLAogICAgICBsYWJlbC5wYWRkaW5nID0gZ3JpZDo6dW5pdCgKICAgICAgICAwLjEyLAogICAgICAgICJsaW5lcyIKICAgICAgKSwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgIGJyZWFrcyA9IDI6NSwKICAgICAgbGFiZWxzID0gcGFzdGUwKAogICAgICAgIDI6NSwKICAgICAgICAi5pS/5YWaIgogICAgICApLAogICAgICBsaW1pdHMgPSBjKAogICAgICAgIDEuNzIsCiAgICAgICAgNS4yOAogICAgICApCiAgICApICsKICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgYnJlYWtzID0gc2VxKAogICAgICAgIHJlbGF0aXZlX2JfbG93ZXIsCiAgICAgICAgcmVsYXRpdmVfYl91cHBlciwKICAgICAgICBieSA9IDAuMDUKICAgICAgKSwKICAgICAgbGFiZWxzID0gbGFiZWxfcGVyY2VudCgKICAgICAgICBhY2N1cmFjeSA9IDEKICAgICAgKSwKICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKAogICAgICAgIG11bHQgPSBjKAogICAgICAgICAgMC4wNSwKICAgICAgICAgIDAuMDgKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgY29vcmRfY2FydGVzaWFuKAogICAgICB5bGltID0gYygKICAgICAgICByZWxhdGl2ZV9iX2xvd2VyLAogICAgICAgIHJlbGF0aXZlX2JfdXBwZXIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJC77ya55u45a++55qE44Gq5pS/5YWa5omL44GM44GL44KK44Gu5q+U6YeNIiwKICAgICAgc3VidGl0bGUgPQogICAgICAgICLmlL/lhZrmiYvjgYzjgYvjgorph43opoHluqYgw7fvvIjmlL/lhZrmiYvjgYzjgYvjgorph43opoHluqbvvIvntYzmuIjmiYvjgYzjgYvjgorph43opoHluqbvvIkiLAogICAgICB4ID0gIuaUv+WFmumBuOaKnuiCouaVsCIsCiAgICAgIHkgPSAi55u45a++55qE44Gq5pS/5YWa5omL44GM44GL44KK5q+U6YeNIgogICAgKSArCiAgICByZWxhdGl2ZV90aGVtZV9qYXBhbmVzZV9idyArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2MgPC0gcmVsYXRpdmVfcGFuZWxfYiArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHBhc3RlMCgKICAgICAgICAiQu+8muebuOWvvueahOOBqiIsCiAgICAgICAgbGV2ZWxzKHJlbGF0aXZlX3BhbmVsX2FfZGF0YSRjdWVfZmFtaWx5KVsxXSwKICAgICAgICAi44Gu5q+U6YeNIgogICAgICApCiAgICApCgogIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAgPC0gKAogICAgcmVsYXRpdmVfcGFuZWxfYSB8CiAgICAgIHJlbGF0aXZlX3BhbmVsX2IKICApICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoCiAgICAgIHdpZHRocyA9IGMoCiAgICAgICAgMSwKICAgICAgICAxCiAgICAgICkKICAgICkKCiAgcHJpbnQoCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwCiAgKQoKICBzYXZlX3Bsb3QoCiAgICAiZmlnX3N0dWR5MV9yZWxhdGl2ZV9jdWVfd2VpZ2h0X2pwX2J3LnBuZyIsCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwLAogICAgd2lkdGggPSAxMS4yLAogICAgaGVpZ2h0ID0gNS40LAogICAgZHBpID0gNDAwCiAgKQoKICBnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IGZpbGUucGF0aCgKICAgICAgb3V0cHV0X2RpciwKICAgICAgImZpZ19zdHVkeTFfcmVsYXRpdmVfY3VlX3dlaWdodF9qcF9idy5wZGYiCiAgICApLAogICAgcGxvdCA9IGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAsCiAgICB3aWR0aCA9IDExLjIsCiAgICBoZWlnaHQgPSA1LjQsCiAgICBkZXZpY2UgPSBnckRldmljZXM6OmNhaXJvX3BkZiwKICAgIGJnID0gIndoaXRlIgogICkKCiAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcCA8LSAoCiAgICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZCB8CiAgICAgIHJlbGF0aXZlX3BhbmVsX2MKICApICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoCiAgICAgIHdpZHRocyA9IGMoCiAgICAgICAgMSwKICAgICAgICAxCiAgICAgICkKICAgICkKCiAgcHJpbnQoCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwCiAgKQoKICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiA8LSBwYXN0ZTAoCiAgICAiZmlnX3N0dWR5IiwKICAgIHN0cmluZ3I6OnN0cl9leHRyYWN0KAogICAgICBzdHVkeV9sYWJlbCwKICAgICAgIlsxMjNdIgogICAgKSwKICAgICJfcmVsYXRpdmVfY3VlX3dlaWdodF9jaG9pY2Vfc2V0X2FkanVzdGVkX2pwX2J3IgogICkKCiAgc2F2ZV9wbG90KAogICAgcGFzdGUwKAogICAgICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiwKICAgICAgIi5wbmciCiAgICApLAogICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcCwKICAgIHdpZHRoID0gMTEuMiwKICAgIGhlaWdodCA9IDUuNCwKICAgIGRwaSA9IDQwMAogICkKCiAgZ2dzYXZlKAogICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgIHBhc3RlMCgKICAgICAgICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiwKICAgICAgICAiLnBkZiIKICAgICAgKQogICAgKSwKICAgIHBsb3QgPSBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwLAogICAgd2lkdGggPSAxMS4yLAogICAgaGVpZ2h0ID0gNS40LAogICAgZGV2aWNlID0gZ3JEZXZpY2VzOjpjYWlyb19wZGYsCiAgICBiZyA9ICJ3aGl0ZSIKICApCgogIHJlbGF0aXZlX2N1ZV9yZXN1bHRzIDwtIGxpc3QoCiAgICBwcmVwYXJlZCA9IHJlbGF0aXZlX2N1ZV9wcmVwYXJlZCwKICAgIG1hcmdpbmFsX21lYW5zID0KICAgICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJG1hcmdpbmFsX21lYW5zLAogICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkYXR0cmlidXRlX2ltcG9ydGFuY2UsCiAgICBjdWVfaW1wb3J0YW5jZSA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgIG9ic2VydmVkX3Nsb3BlcyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZF9zbG9wZXMsCiAgICBjb25kaXRpb25fYm9vdHN0cmFwID0KICAgICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9ib290c3RyYXAsCiAgICBzbG9wZV9ib290c3RyYXAgPQogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwLAogICAgY29uZGl0aW9uX2ludGVydmFscyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzLAogICAgc2xvcGVfaW5mZXJlbmNlID0KICAgICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2luZmVyZW5jZSwKICAgIHByaW1hcnlfcmVzdWx0ID0KICAgICAgcmVsYXRpdmVfY3VlX3ByaW1hcnlfcmVzdWx0LAogICAgcGxvdHMgPSBsaXN0KAogICAgICBhYnNvbHV0ZV9pbXBvcnRhbmNlID0gcmVsYXRpdmVfcGFuZWxfYSwKICAgICAgY2hvaWNlX3NldF9hZGp1c3RlZF9pbXBvcnRhbmNlID0KICAgICAgICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZCwKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0ID0gcmVsYXRpdmVfcGFuZWxfYiwKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhbmVsX2MgPQogICAgICAgIHJlbGF0aXZlX3BhbmVsX2MsCiAgICAgIGNvbWJpbmVkID0gZmlndXJlX3JlbGF0aXZlX3dlaWdodF9qcCwKICAgICAgY29tYmluZWRfd2l0aF9jaG9pY2Vfc2V0X2FkanVzdG1lbnQgPQogICAgICAgIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfYWRqdXN0ZWRfanAKICAgICkKICApCgogIHNhdmVSRFMoCiAgICByZWxhdGl2ZV9jdWVfcmVzdWx0cywKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJzdHVkeTFfcmVsYXRpdmVfY3VlX3Jlc3VsdHMucmRzIgogICAgKQogICkKCgogIHNhdmVSRFMoCiAgICBsaXN0KAogICAgICBzZXR0aW5ncyA9IGxpc3QoCiAgICAgICAgcmVxdWlyZV9pbml0aWFsX2NvbnNlbnQgPSByZXF1aXJlX2luaXRpYWxfY29uc2VudCwKICAgICAgICByZXF1aXJlX2ZpbmFsX2NvbnNlbnQgPSByZXF1aXJlX2ZpbmFsX2NvbnNlbnQsCiAgICAgICAgcmVxdWlyZV9hdHRlbnRpb25fY2hlY2sgPSByZXF1aXJlX2F0dGVudGlvbl9jaGVjaywKICAgICAgICByZXF1aXJlX21hbmlwdWxhdGlvbl9jaGVjayA9IHJlcXVpcmVfbWFuaXB1bGF0aW9uX2NoZWNrCiAgICAgICksCiAgICAgIHNhbXBsZV9mbG93ID0gc2FtcGxlX2Zsb3csCiAgICAgIG5fYnlfcGFydHkgPSBuX2J5X3BhcnR5LAogICAgICB2YWxpZF9pZHMgPSB2YWxpZF9pZHMsCiAgICAgIGNvbmpvaW50X2FsbCA9IGNvbmpvaW50X2FsbCwKICAgICAgY29uam9pbnRfYWxsX20gPSBjb25qb2ludF9hbGxfbSwKICAgICAgY292YXJfaWQgPSBjb3Zhcl9pZCwKICAgICAgbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YgPSBtb2RlbHNfYnlfcGFydHlfbl9ub2NvdiwKICAgICAgbW9kZWxzX2J5X3BhcnR5X25fY292ID0gbW9kZWxzX2J5X3BhcnR5X25fY292LAogICAgICBtX2ludGVyYWN0aW9uID0gbV9pbnRlcmFjdGlvbiwKICAgICAgbW9kZWxzX2Nsb2dpdF9ub2NvdiA9IG1vZGVsc19jbG9naXRfbm9jb3YsCiAgICAgIHJlbGF0aXZlX2N1ZSA9IHJlbGF0aXZlX2N1ZV9yZXN1bHRzLAogICAgICBwbG90cyA9IGxpc3QoCiAgICAgICAgYW1jZV9jb3YgPSBwX2FtY2VfY292X21haW4sCiAgICAgICAgYW1jZV9ub2NvdiA9IHBfYW1jZV9ub2Nvdl9hcHBlbmRpeCwKICAgICAgICBpbnRlcmFjdGlvbiA9IHBfaW50ZXJhY3Rpb24sCiAgICAgICAgaGVhdG1hcCA9IHBfaGVhdF9hbWNlLAogICAgICAgIGhlYXRtYXBfcmFuayA9IHBfaGVhdF9hbWNlX3JhbmssCiAgICAgICAgY2xvZ2l0X29kZHNfcmF0aW8gPSBwX2Nsb2dpdF9vciwKICAgICAgICByZWxhdGl2ZV9jdWVfd2VpZ2h0ID0gZmlndXJlX3JlbGF0aXZlX3dlaWdodF9qcCwKICAgICAgICByZWxhdGl2ZV9jdWVfd2VpZ2h0X2Nob2ljZV9zZXRfYWRqdXN0ZWQgPQogICAgICAgICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcAogICAgICApCiAgICApLAogICAgZmlsZSA9IGZpbGUucGF0aChvdXRwdXRfZGlyLCAic3R1ZHkxX2FuYWx5c2lzX29iamVjdHMucmRzIikKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc2Vzc2lvbkluZm8oKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgInNlc3Npb25JbmZvLnR4dCIpCiAgKQoKICBjYXQoIgpEb25lOiAiLCBub3JtYWxpemVQYXRoKG91dHB1dF9kaXIpLCAiCiIsIHNlcCA9ICIiKQoKICBlbnZpcm9ubWVudCgpCn0pCgoKYGBgCgojIyBBLjMg5a6f6aiTMu+8muacrOaWh+OBruWbszYKCmBgYHtyIGEzLXN0dWR5Mi1jb2RlLCBldmFsPXBhcmFtcyRydW5fYW5hbHlzaXMsIHJlc3VsdHM9J2hpZGUnLCBmaWcuc2hvdz0naGlkZSd9CiMg5pys5paH44Kz44O844OJCnN0dWR5Ml9lbnYgPC0gbG9jYWwoewpyZXF1aXJlZF9wYWNrYWdlcyA8LSBjKAogICAgImRwbHlyIiwKICAgICJ0aWR5ciIsCiAgICAic3RyaW5nciIsCiAgICAicHVycnIiLAogICAgInJlYWRyIiwKICAgICJmaXhlc3QiLAogICAgInRpYmJsZSIsCiAgICAiZm9yY2F0cyIsCiAgICAiZ2dwbG90MiIsCiAgICAic2NhbGVzIiwKICAgICJzdXJ2aXZhbCIsCiAgICAiZ2d0ZXh0IiwKICAgICJwYXRjaHdvcmsiCiAgKQoKICBtaXNzaW5nX3BhY2thZ2VzIDwtIHJlcXVpcmVkX3BhY2thZ2VzWwogICAgIXZhcHBseShyZXF1aXJlZF9wYWNrYWdlcywgcmVxdWlyZU5hbWVzcGFjZSwgbG9naWNhbCgxKSwgcXVpZXRseSA9IFRSVUUpCiAgXQoKICBpZiAobGVuZ3RoKG1pc3NpbmdfcGFja2FnZXMpID4gMCkgewogICAgc3RvcCgiTm8gcGFja2FnZXMiKQogIH0KCiAgbGlicmFyeShkcGx5cikKICBsaWJyYXJ5KHRpZHlyKQogIGxpYnJhcnkoc3RyaW5ncikKICBsaWJyYXJ5KHB1cnJyKQogIGxpYnJhcnkocmVhZHIpCiAgbGlicmFyeShmaXhlc3QpCiAgbGlicmFyeSh0aWJibGUpCiAgbGlicmFyeShmb3JjYXRzKQogIGxpYnJhcnkoZ2dwbG90MikKICBsaWJyYXJ5KHNjYWxlcykKICBsaWJyYXJ5KHN1cnZpdmFsKQogIGxpYnJhcnkocGF0Y2h3b3JrKQoKICBkYXRhX2ZpbGUgPC0gdW5pZmllZF9jb25maWckc3R1ZHkyJGRhdGFfZmlsZQogIG91dHB1dF9kaXIgPC0gdW5pZmllZF9jb25maWckc3R1ZHkyJG91dHB1dF9kaXIKCiAgZGlyLmNyZWF0ZShvdXRwdXRfZGlyLCBzaG93V2FybmluZ3MgPSBGQUxTRSwgcmVjdXJzaXZlID0gVFJVRSkKCiAgcmVxdWlyZV9pbml0aWFsX2NvbnNlbnQgPC0gVFJVRQogIHJlcXVpcmVfZmluYWxfY29uc2VudCA8LSBUUlVFCiAgZmluYWxfY29uc2VudF92YXIgPC0gIlE4LjEiCgogIHJlcXVpcmVfYXR0ZW50aW9uX2NoZWNrIDwtIFRSVUUKICByZXF1aXJlX21hbmlwdWxhdGlvbl9jaGVjayA8LSBUUlVFCgogIGF0dGVudGlvbl9jaGVja192YXIgPC0gIlEyNS4xXzExIgogIGF0dGVudGlvbl9jaGVja19jb3JyZWN0IDwtICIzIgoKICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IgPC0gdW5pZmllZF9jb25maWckcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CCiAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9zZWVkIDwtIHVuaWZpZWRfY29uZmlnJHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfc2VlZCArIDJMCiAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9wcm9ncmVzc19ldmVyeSA8LSB1bmlmaWVkX2NvbmZpZyRyZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3Byb2dyZXNzX2V2ZXJ5CgogIHJlcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAgPC0gdW5pZmllZF9jb25maWckcmVydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcAoKCiAgbm9ybV90ZXh0IDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggJT4lCiAgICAgIGFzLmNoYXJhY3RlcigpICU+JQogICAgICBzdHJfc3F1aXNoKCkgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgi772eIiwgIn4iKSAlPiUKICAgICAgc3RyX3JlcGxhY2VfYWxsKCLjgJwiLCAifiIpCiAgfQoKICBhc19udW0gPC0gZnVuY3Rpb24oeCkgewogICAgc3VwcHJlc3NXYXJuaW5ncyhyZWFkcjo6cGFyc2VfbnVtYmVyKG5vcm1fdGV4dCh4KSkpCiAgfQoKICBpc19yZXNwb25zZV9jb2RlIDwtIGZ1bmN0aW9uKHgsIGNvZGUpIHsKICAgIHhfbm9ybSA8LSBub3JtX3RleHQoeCkKICAgIGNvZGVfY2hyIDwtIGFzLmNoYXJhY3Rlcihjb2RlKQoKICAgIHhfbm9ybSA9PSBjb2RlX2NociB8CiAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QoeF9ub3JtLCBwYXN0ZTAoIlxcKCIsIGNvZGVfY2hyLCAiXFwpJCIpKQogIH0KCiAgZmlyc3RfZXhpc3RpbmcgPC0gZnVuY3Rpb24oZGF0LCBjYW5kaWRhdGVzKSB7CiAgICBvdXQgPC0gY2FuZGlkYXRlc1tjYW5kaWRhdGVzICVpbiUgbmFtZXMoZGF0KV0KICAgIGlmIChsZW5ndGgob3V0KSA9PSAwKSBOQV9jaGFyYWN0ZXJfIGVsc2Ugb3V0WzFdCiAgfQoKICBnZXRfdmFyIDwtIGZ1bmN0aW9uKGRhdCwgY2FuZGlkYXRlcykgewogICAgdiA8LSBmaXJzdF9leGlzdGluZyhkYXQsIGNhbmRpZGF0ZXMpCiAgICBpZiAoaXMubmEodikpIHsKICAgICAgcmVwKE5BX2NoYXJhY3Rlcl8sIG5yb3coZGF0KSkKICAgIH0gZWxzZSB7CiAgICAgIGRhdFtbdl1dCiAgICB9CiAgfQoKICByZWxldmVsX2lmX3ByZXNlbnQgPC0gZnVuY3Rpb24oeCwgcmVmKSB7CiAgICB4IDwtIGZhY3Rvcih4KQogICAgaWYgKHJlZiAlaW4lIGxldmVscyh4KSkgewogICAgICByZWxldmVsKHgsIHJlZiA9IHJlZikKICAgIH0gZWxzZSB7CiAgICAgIHgKICAgIH0KICB9CgogIGZhY3Rvcl9taXNzIDwtIGZ1bmN0aW9uKHgsIG1pc3MgPSAi5qyg5pCN44O754Sh5Zue562UIikgewogICAgeCA8LSBub3JtX3RleHQoeCkKICAgIHhbaXMubmEoeCkgfCB4ID09ICIiIHwgeCA9PSAiTkEiXSA8LSBtaXNzCiAgICBmYWN0b3IoeCkKICB9CgogIG1lYW5faW1wdXRlIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0gYXMubnVtZXJpYyh4KQogICAgbWlzcyA8LSBhcy5pbnRlZ2VyKGlzLm5hKHgpKQoKICAgIGlmIChhbGwoaXMubmEoeCkpKSB7CiAgICAgIHZhbHVlIDwtIHgKICAgIH0gZWxzZSB7CiAgICAgIHZhbHVlIDwtIGlmZWxzZShpcy5uYSh4KSwgbWVhbih4LCBuYS5ybSA9IFRSVUUpLCB4KQogICAgfQoKICAgIGxpc3QodmFsdWUgPSB2YWx1ZSwgbWlzcyA9IG1pc3MpCiAgfQoKICB3cml0ZV9jc3Zfc2FmZWx5IDwtIGZ1bmN0aW9uKHgsIGZpbGVuYW1lKSB7CiAgICByZWFkcjo6d3JpdGVfY3N2KHgsIGZpbGUucGF0aChvdXRwdXRfZGlyLCBmaWxlbmFtZSksIG5hID0gIiIpCiAgfQoKICBzYXZlX3Bsb3QgPC0gZnVuY3Rpb24oZmlsZW5hbWUsIHBsb3QsIHdpZHRoLCBoZWlnaHQsIGRwaSA9IDMwMCkgewogICAgZ2dwbG90Mjo6Z2dzYXZlKAogICAgICBmaWxlbmFtZSA9IGZpbGUucGF0aChvdXRwdXRfZGlyLCBmaWxlbmFtZSksCiAgICAgIHBsb3QgPSBwbG90LAogICAgICB3aWR0aCA9IHdpZHRoLAogICAgICBoZWlnaHQgPSBoZWlnaHQsCiAgICAgIGRwaSA9IGRwaQogICAgKQogIH0KCgogIGlmICghZmlsZS5leGlzdHMoZGF0YV9maWxlKSkgewogICAgc3RvcCgiQ2hlY2sgZGF0YSIpCiAgfQoKICByYXcgPC0gcmVhZHI6OnJlYWRfY3N2KAogICAgZGF0YV9maWxlLAogICAgY29sX3R5cGVzID0gY29scyguZGVmYXVsdCA9IGNvbF9jaGFyYWN0ZXIoKSksCiAgICBzaG93X2NvbF90eXBlcyA9IEZBTFNFLAogICAgbmFtZV9yZXBhaXIgPSAibWluaW1hbCIKICApCgoKICBpZiAocmVxdWlyZV9maW5hbF9jb25zZW50KSB7CiAgICBmaW5hbF9jb25zZW50X3ZhciA8LSBkZXRlY3RfZmluYWxfY29uc2VudF9jb2x1bW4oCiAgICAgIHJhdyA9IHJhdywKICAgICAgcHJlZmVycmVkX2NhbmRpZGF0ZXMgPSBjKCJROC4xIiwgIlE5LjEiLCAiUTEwLjEiKSwKICAgICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgMiIKICAgICkKICB9CgogIGlmIChyZXF1aXJlX2F0dGVudGlvbl9jaGVjaykgewogICAgYXR0ZW50aW9uX2NoZWNrX3ZhciA8LSBkZXRlY3RfYXR0ZW50aW9uX2NoZWNrX2NvbHVtbigKICAgICAgcmF3ID0gcmF3LAogICAgICBwcmVmZXJyZWRfY2FuZGlkYXRlcyA9IGMoIlEyNS4xXzExIiwgIlEyNS4xXzEwIiksCiAgICAgIHN0dWR5X2xhYmVsID0gIlN0dWR5IDIiCiAgICApCiAgfQoKICBkZl9oZWFkZXJfcmVtb3ZlZCA8LSByYXcgJT4lCiAgICBmaWx0ZXIoCiAgICAgICFpcy5uYShSZXNwb25zZUlkKSwKICAgICAgUmVzcG9uc2VJZCAhPSAiIiwKICAgICAgIXN0cl9kZXRlY3QoCiAgICAgICAgbm9ybV90ZXh0KFJlc3BvbnNlSWQpLAogICAgICAgICJeKFJlc3BvbnNlIElEfOWbnuetlElEKSR8SW1wb3J0SWQiCiAgICAgICkKICAgICkgJT4lCiAgICBtdXRhdGUoSUQgPSBhcy5jaGFyYWN0ZXIoUmVzcG9uc2VJZCkpCgogIGR1cGxpY2F0ZV9pZHMgPC0gZGZfaGVhZGVyX3JlbW92ZWQgJT4lCiAgICBjb3VudChJRCkgJT4lCiAgICBmaWx0ZXIobiA+IDEpCgogIGlmIChucm93KGR1cGxpY2F0ZV9pZHMpID4gMCkgewogICAgcHJpbnQoZHVwbGljYXRlX2lkcykKICAgIHN0b3AoIkNoZWNrIikKICB9CgogIHNhbXBsZV9mbG93IDwtIHRpYmJsZSgKICAgIHN0YWdlID0gIlF1YWx0cmljc+izquWVj+aWh+ihjOOCkumZpOWkluW+jCIsCiAgICBuID0gbnJvdyhkZl9oZWFkZXJfcmVtb3ZlZCkKICApCgogIGRmIDwtIGRmX2hlYWRlcl9yZW1vdmVkCgogIGlmIChyZXF1aXJlX2luaXRpYWxfY29uc2VudCkgewogICAgaWYgKCEiUTEuMSIgJWluJSBuYW1lcyhkZikpIHsKICAgICAgc3RvcCgiQ2hlY2sgaW5pdGlhbCBjb25zZW50IikKICAgIH0KCiAgICBkZiA8LSBkZiAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIGlzX3Jlc3BvbnNlX2NvZGUoUTEuMSwgMSkgfAogICAgICAgICAgc3RyX2RldGVjdChub3JtX3RleHQoUTEuMSksICLotqPml6jjgavlkIzmhI/jgZfjgaYuKuWNlOWKm+OBmeOCiyIpCiAgICAgICkKCiAgICBzYW1wbGVfZmxvdyA8LSBiaW5kX3Jvd3MoCiAgICAgIHNhbXBsZV9mbG93LAogICAgICB0aWJibGUoc3RhZ2UgPSAi5Yid5Zue5ZCM5oSPIFExLjEgPSAxIiwgbiA9IG5yb3coZGYpKQogICAgKQogIH0KCiAgaWYgKHJlcXVpcmVfZmluYWxfY29uc2VudCkgewogICAgaWYgKGlzLm5hKGZpbmFsX2NvbnNlbnRfdmFyKSB8fCAhZmluYWxfY29uc2VudF92YXIgJWluJSBuYW1lcyhkZikpIHsKICAgICAgc3RvcCgiQ2hlY2sgZmluYWwgY29uc2VudCIpCiAgICB9CgogICAgZGYgPC0gZGYgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBpc19yZXNwb25zZV9jb2RlKC5kYXRhW1tmaW5hbF9jb25zZW50X3Zhcl1dLCAxKSB8CiAgICAgICAgICBzdHJfZGV0ZWN0KAogICAgICAgICAgICBub3JtX3RleHQoLmRhdGFbW2ZpbmFsX2NvbnNlbnRfdmFyXV0pLAogICAgICAgICAgICAi5ZCM5oSP44GXLirlm57nrZTntZDmnpzjgpLpgIHkv6HjgZnjgosiCiAgICAgICAgICApCiAgICAgICkKCiAgICBzYW1wbGVfZmxvdyA8LSBiaW5kX3Jvd3MoCiAgICAgIHNhbXBsZV9mbG93LAogICAgICB0aWJibGUoCiAgICAgICAgc3RhZ2UgPSBwYXN0ZTAoIuacgOe1guWQjOaEjyAiLCBmaW5hbF9jb25zZW50X3ZhciwgIiA9IDEiKSwKICAgICAgICBuID0gbnJvdyhkZikKICAgICAgKQogICAgKQogIH0KCiAgaWYgKHJlcXVpcmVfYXR0ZW50aW9uX2NoZWNrKSB7CiAgICBpZiAoIWF0dGVudGlvbl9jaGVja192YXIgJWluJSBuYW1lcyhkZikpIHsKICAgICAgc3RvcCgiQ2hlY2sgYXR0ZW50aW9uIGl0ZW0iKQogICAgfQoKICAgIGF0dGVudGlvbl9jaGVja19jb3JyZWN0IDwtIGRldGVjdF9hdHRlbnRpb25fY29ycmVjdF9jb2RlKAogICAgICBkZltbYXR0ZW50aW9uX2NoZWNrX3Zhcl1dLAogICAgICBkaXNwbGF5ZWRfYW5zd2VyID0gM0wsCiAgICAgIHJlY29kZWRfYW5zd2VyID0gNkwsCiAgICAgIHN0dWR5X2xhYmVsID0gIlN0dWR5IDIiCiAgICApCgogICAgZGYgPC0gZGYgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBpc19yZXNwb25zZV9jb2RlKAogICAgICAgICAgLmRhdGFbW2F0dGVudGlvbl9jaGVja192YXJdXSwKICAgICAgICAgIGF0dGVudGlvbl9jaGVja19jb3JyZWN0CiAgICAgICAgKQogICAgICApCgogICAgc2FtcGxlX2Zsb3cgPC0gYmluZF9yb3dzKAogICAgICBzYW1wbGVfZmxvdywKICAgICAgdGliYmxlKAogICAgICAgIHN0YWdlID0gcGFzdGUwKAogICAgICAgICAgIuaMh+ekuumgheebruato+etlO+8iCIsCiAgICAgICAgICBhdHRlbnRpb25fY2hlY2tfdmFyLAogICAgICAgICAgIuOAgeS/neWtmOOCs+ODvOODiT0iLAogICAgICAgICAgYXR0ZW50aW9uX2NoZWNrX2NvcnJlY3QsCiAgICAgICAgICAi77yJIgogICAgICAgICksCiAgICAgICAgbiA9IG5yb3coZGYpCiAgICAgICkKICAgICkKICB9CgogIHByaW50KHNhbXBsZV9mbG93KQogIHdyaXRlX2Nzdl9zYWZlbHkoc2FtcGxlX2Zsb3csICJzYW1wbGVfZmxvd19iZWZvcmVfY29uam9pbnQuY3N2IikKCgogIGNob2ljZV9tYXAgPC0gZGV0ZWN0X2NvbmpvaW50X2Nob2ljZV9tYXAoCiAgICByYXcgPSByYXcsCiAgICBwYXJ0eV9udW1iZXJzID0gMjo1LAogICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgMiIKICApCgogIG1hbmlwdWxhdGlvbl9tYXAgPC0gZGV0ZWN0X21hbmlwdWxhdGlvbl9tYXAoCiAgICByYXcgPSByYXcsCiAgICBjaG9pY2VfbWFwID0gY2hvaWNlX21hcCwKICAgIHN0dWR5X2xhYmVsID0gIlN0dWR5IDIiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KGNob2ljZV9tYXAsICJkZXRlY3RlZF9jaG9pY2VfcXVlc3Rpb25fbWFwLmNzdiIpCiAgd3JpdGVfY3N2X3NhZmVseShtYW5pcHVsYXRpb25fbWFwLCAiZGV0ZWN0ZWRfbWFuaXB1bGF0aW9uX3F1ZXN0aW9uX21hcC5jc3YiKQoKCiAgbGV2ZWxfdG9fYXR0cl92YXIgPC0gZnVuY3Rpb24oeCkgewogICAgeCA8LSBub3JtX3RleHQoeCkKCiAgICBjYXNlX3doZW4oCiAgICAgIHggJWluJSBjKCLlj7PmtL7jg7vkv53lrojnmoQiLCAi5Lit6YGTIiwgIuW3pua0vuODu+mdqeaWsOeahCIpIH4KICAgICAgICAicG9saWN5X3Bvc2l0aW9uIiwKCiAgICAgIHggJWluJSBjKCLkuI7lhZoiLCAi6YeO5YWaIikgfgogICAgICAgICJnb3Zlcm5tZW50X3N0YXR1cyIsCgogICAgICBzdHJfZGV0ZWN0KHgsICJHRFDmiJDplbfnjociKSB+CiAgICAgICAgImdkcF9ncm93dGgiLAoKICAgICAgc3RyX2RldGVjdCh4LCAi5pel57WM5bmz5Z2HIikgfgogICAgICAgICJuaWtrZWkiLAoKICAgICAgeCAlaW4lIGMoIjEw5Lul5LiLIiwgIjEwfjQ5IiwgIjUwfjk5IiwgIjEwMH4xOTkiLCAiMjAw5Lul5LiKIikgfgogICAgICAgICJzZWF0cyIsCgogICAgICBzdHJfZGV0ZWN0KHgsICJDUEl854mp5L6hIikgfgogICAgICAgICJjcGkiLAoKICAgICAgc3RyX2RldGVjdCh4LCAi5aSx5qWt546HfOmbh+eUqCIpIH4KICAgICAgICAidW5lbXBsb3ltZW50IiwKCiAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfCiAgICApCiAgfQoKICByZXF1aXJlZF9hdHRyX3ZhcnMgPC0gYygKICAgICJwb2xpY3lfcG9zaXRpb24iLAogICAgImdvdmVybm1lbnRfc3RhdHVzIiwKICAgICJnZHBfZ3Jvd3RoIiwKICAgICJuaWtrZWkiLAogICAgInNlYXRzIiwKICAgICJjcGkiLAogICAgInVuZW1wbG95bWVudCIKICApCgogIGFsbG93ZWRfbGV2ZWxzIDwtIGxpc3QoCiAgICBwb2xpY3lfcG9zaXRpb24gPSBjKCLlj7PmtL7jg7vkv53lrojnmoQiLCAi5Lit6YGTIiwgIuW3pua0vuODu+mdqeaWsOeahCIpLAogICAgZ292ZXJubWVudF9zdGF0dXMgPSBjKCLkuI7lhZoiLCAi6YeO5YWaIiksCiAgICBnZHBfZ3Jvd3RoID0gYygKICAgICAgIkdEUOaIkOmVt+eOh8KxMO+8hSIsCiAgICAgICJHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICAgIkdEUOaIkOmVt+eOh+ODnuOCpOODiuOCuTHvvIUiCiAgICApLAogICAgbmlra2VpID0gYygKICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODl+ODqeOCuTEwMDDlhoYiLAogICAgICAi5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44Oe44Kk44OK44K5MTAwMOWGhiIsCiAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiCiAgICApLAogICAgc2VhdHMgPSBjKCIxMOS7peS4iyIsICIxMH40OSIsICI1MH45OSIsICIxMDB+MTk5IiwgIjIwMOS7peS4iiIpLAogICAgY3BpID0gYygKICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIsCiAgICAgICJDUEnliY3mnJ/mr5Tjg5fjg6njgrkx44Od44Kk44Oz44OIIiwKICAgICAgIkNQSeWJjeacn+avlOODnuOCpOODiuOCuTHjg53jgqTjg7Pjg4giCiAgICApLAogICAgdW5lbXBsb3ltZW50ID0gYygKICAgICAgIuWksealreeOh+WJjeacn+avlMKxMO+8hSIsCiAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg5fjg6njgrkx77yFIiwKICAgICAgIuWksealreeOh+WJjeacn+avlOODnuOCpOODiuOCuTHvvIUiCiAgICApCiAgKQoKCiAgbWFrZV9wcm9maWxlX2xvbmcgPC0gZnVuY3Rpb24oZGF0LCBuX3BhcnR5KSB7CgogICAgbWFwX24gPC0gY2hvaWNlX21hcCAlPiUKICAgICAgZmlsdGVyKHBhcnR5X24gPT0gbl9wYXJ0eSkKCiAgICBxdmFycyA8LSBtYXBfbiRjaG9pY2VfdmFyCgogICAgbWlzc2luZ19xIDwtIHNldGRpZmYocXZhcnMsIG5hbWVzKGRhdCkpCiAgICBpZiAobGVuZ3RoKG1pc3NpbmdfcSkgPiAwKSB7CiAgICAgIHN0b3AoIkNoZWNrIGNob2ljZSBjb2x1bW5zIikKICAgIH0KCiAgICBkYXRfbiA8LSBkYXQgJT4lCiAgICAgIGZpbHRlcihpZl9hbnkoYWxsX29mKHF2YXJzKSwgfiAhaXMubmEoLngpICYgbm9ybV90ZXh0KC54KSAhPSAiIikpCgogICAgaWYgKHJlcXVpcmVfbWFuaXB1bGF0aW9uX2NoZWNrKSB7CiAgICAgIG1hbmlwdWxhdGlvbl9yb3cgPC0gbWFuaXB1bGF0aW9uX21hcCAlPiUKICAgICAgICBmaWx0ZXIocGFydHlfbiA9PSBuX3BhcnR5KQoKICAgICAgbWFuaXB1bGF0aW9uX3ZhciA8LSBtYW5pcHVsYXRpb25fcm93JG1hbmlwdWxhdGlvbl92YXIKICAgICAgY29ycmVjdF9hbnN3ZXIgPC0gbWFuaXB1bGF0aW9uX3JvdyRjb3JyZWN0X2Fuc3dlcgoKICAgICAgaWYgKCFtYW5pcHVsYXRpb25fdmFyICVpbiUgbmFtZXMoZGF0X24pKSB7CiAgICAgICAgc3RvcCgiQ2hlY2sgbWFuaXB1bGF0aW9uIGl0ZW0iKQogICAgICB9CgogICAgICBkYXRfbiA8LSBkYXRfbiAlPiUKICAgICAgICBmaWx0ZXIoCiAgICAgICAgICBpc19yZXNwb25zZV9jb2RlKAogICAgICAgICAgICAuZGF0YVtbbWFuaXB1bGF0aW9uX3Zhcl1dLAogICAgICAgICAgICBjb3JyZWN0X2Fuc3dlcgogICAgICAgICAgKQogICAgICAgICkKICAgIH0KCgogICAgY2hvaWNlX2xvbmcgPC0gZGF0X24gJT4lCiAgICAgIHNlbGVjdChJRCwgYWxsX29mKHF2YXJzKSkgJT4lCiAgICAgIHBpdm90X2xvbmdlcigKICAgICAgICBjb2xzID0gYWxsX29mKHF2YXJzKSwKICAgICAgICBuYW1lc190byA9ICJjaG9pY2VfdmFyIiwKICAgICAgICB2YWx1ZXNfdG8gPSAiY2hvaWNlX3JhdyIKICAgICAgKSAlPiUKICAgICAgbGVmdF9qb2luKG1hcF9uLCBieSA9ICJjaG9pY2VfdmFyIikgJT4lCiAgICAgIG11dGF0ZShjaG9pY2UgPSBwYXJzZV9jaG9pY2VfcG9zaXRpb24oY2hvaWNlX3JhdykpICU+JQogICAgICBmaWx0ZXIoIWlzLm5hKGNob2ljZSkpICU+JQogICAgICBzZWxlY3QoSUQsIHBhcnR5X24sIHRhc2ssIGNob2ljZSkKCiAgICBpbnZhbGlkX2Nob2ljZSA8LSBjaG9pY2VfbG9uZyAlPiUKICAgICAgZmlsdGVyKGNob2ljZSA8IDEgfCBjaG9pY2UgPiBuX3BhcnR5KQoKICAgIGlmIChucm93KGludmFsaWRfY2hvaWNlKSA+IDApIHsKICAgICAgcHJpbnQoaW52YWxpZF9jaG9pY2UpCiAgICAgIHN0b3AoIkNoZWNrIGNob2ljZSB2YWx1ZXMiKQogICAgfQoKICAgIGR1cGxpY2F0ZV9jaG9pY2UgPC0gY2hvaWNlX2xvbmcgJT4lCiAgICAgIGNvdW50KElELCB0YXNrKSAlPiUKICAgICAgZmlsdGVyKG4gIT0gMSkKCiAgICBpZiAobnJvdyhkdXBsaWNhdGVfY2hvaWNlKSA+IDApIHsKICAgICAgcHJpbnQoZHVwbGljYXRlX2Nob2ljZSkKICAgICAgc3RvcCgiQ2hlY2sgZHVwbGljYXRlIGNob2ljZXMiKQogICAgfQoKCiAgICBsZXZlbF9yZWdleCA8LSBwYXN0ZTAoCiAgICAgICJeUzJfUCIsIG5fcGFydHksCiAgICAgICJfRl8oWzEtNV0pXyhbMS0iLCBuX3BhcnR5LCAiXSlfKFsxLTddKSQiCiAgICApCgogICAgbGV2ZWxfY29scyA8LSBuYW1lcyhkYXRfbilbc3RyX2RldGVjdChuYW1lcyhkYXRfbiksIGxldmVsX3JlZ2V4KV0KCiAgICBleHBlY3RlZF9sZXZlbF9jb2xzIDwtIDUgKiBuX3BhcnR5ICogNwogICAgaWYgKGxlbmd0aChsZXZlbF9jb2xzKSAhPSBleHBlY3RlZF9sZXZlbF9jb2xzKSB7CiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIGxldmVsX2xvbmcgPC0gZGF0X24gJT4lCiAgICAgIHNlbGVjdChJRCwgYWxsX29mKGxldmVsX2NvbHMpKSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2YobGV2ZWxfY29scyksCiAgICAgICAgbmFtZXNfdG8gPSAiZnZhciIsCiAgICAgICAgdmFsdWVzX3RvID0gImxldmVsIgogICAgICApICU+JQogICAgICBleHRyYWN0KAogICAgICAgIGZ2YXIsCiAgICAgICAgaW50byA9IGMoInRhc2siLCAicHJvZmlsZSIsICJhdHRyX29yZGVyIiksCiAgICAgICAgcmVnZXggPSBsZXZlbF9yZWdleCwKICAgICAgICBjb252ZXJ0ID0gVFJVRQogICAgICApICU+JQogICAgICBtdXRhdGUobGV2ZWwgPSBub3JtX3RleHQobGV2ZWwpKSAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIHRhc2sgJWluJSAxOjUsCiAgICAgICAgcHJvZmlsZSAlaW4lIDE6bl9wYXJ0eSwKICAgICAgICBhdHRyX29yZGVyICVpbiUgMTo3LAogICAgICAgICFpcy5uYShsZXZlbCksCiAgICAgICAgbGV2ZWwgIT0gIiIKICAgICAgKSAlPiUKICAgICAgbXV0YXRlKGF0dHJfdmFyID0gbGV2ZWxfdG9fYXR0cl92YXIobGV2ZWwpKQoKICAgIHVua25vd25fbGV2ZWxzIDwtIGxldmVsX2xvbmcgJT4lCiAgICAgIGZpbHRlcihpcy5uYShhdHRyX3ZhcikpICU+JQogICAgICBkaXN0aW5jdChsZXZlbCkKCiAgICBpZiAobnJvdyh1bmtub3duX2xldmVscykgPiAwKSB7CiAgICAgIHByaW50KHVua25vd25fbGV2ZWxzKQogICAgICBzdG9wKCJDaGVjayBhdHRyaWJ1dGVzIikKICAgIH0KCiAgICBwcm9maWxlX2F0dHJpYnV0ZV9jb3VudCA8LSBsZXZlbF9sb25nICU+JQogICAgICBjb3VudChJRCwgdGFzaywgcHJvZmlsZSwgbmFtZSA9ICJuX2F0dHJpYnV0ZV9yb3dzIikgJT4lCiAgICAgIGZpbHRlcihuX2F0dHJpYnV0ZV9yb3dzICE9IDcpCgogICAgaWYgKG5yb3cocHJvZmlsZV9hdHRyaWJ1dGVfY291bnQpID4gMCkgewogICAgICBwcmludChoZWFkKHByb2ZpbGVfYXR0cmlidXRlX2NvdW50LCA1MCkpCiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIGR1cGxpY2F0ZV9hdHRyaWJ1dGUgPC0gbGV2ZWxfbG9uZyAlPiUKICAgICAgY291bnQoSUQsIHRhc2ssIHByb2ZpbGUsIGF0dHJfdmFyKSAlPiUKICAgICAgZmlsdGVyKG4gIT0gMSkKCiAgICBpZiAobnJvdyhkdXBsaWNhdGVfYXR0cmlidXRlKSA+IDApIHsKICAgICAgcHJpbnQoaGVhZChkdXBsaWNhdGVfYXR0cmlidXRlLCA1MCkpCiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKCiAgICBwcm9maWxlX3dpZGUgPC0gbGV2ZWxfbG9uZyAlPiUKICAgICAgaW5uZXJfam9pbihjaG9pY2VfbG9uZywgYnkgPSBjKCJJRCIsICJ0YXNrIikpICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgcGFydHlfbiA9IG5fcGFydHksCiAgICAgICAgc2VsZWN0ZWQgPSBhcy5pbnRlZ2VyKHByb2ZpbGUgPT0gY2hvaWNlKSwKICAgICAgICB0YXNrX2lkID0gcGFzdGUoSUQsIHBhcnR5X24sIHRhc2ssIHNlcCA9ICJfIiksCiAgICAgICAgcHJvZmlsZV9pZCA9IHBhc3RlKElELCBwYXJ0eV9uLCB0YXNrLCBwcm9maWxlLCBzZXAgPSAiXyIpCiAgICAgICkgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBJRCwgcGFydHlfbiwgdGFzaywgcHJvZmlsZSwgY2hvaWNlLCBzZWxlY3RlZCwKICAgICAgICB0YXNrX2lkLCBwcm9maWxlX2lkLCBhdHRyX3ZhciwgbGV2ZWwKICAgICAgKSAlPiUKICAgICAgcGl2b3Rfd2lkZXIoCiAgICAgICAgbmFtZXNfZnJvbSA9IGF0dHJfdmFyLAogICAgICAgIHZhbHVlc19mcm9tID0gbGV2ZWwsCiAgICAgICAgdmFsdWVzX2ZuID0gbGlzdChsZXZlbCA9IH4gZmlyc3QoLngpKQogICAgICApCgogICAgbWlzc2luZ19hdHRyIDwtIHNldGRpZmYocmVxdWlyZWRfYXR0cl92YXJzLCBuYW1lcyhwcm9maWxlX3dpZGUpKQoKICAgIGlmIChsZW5ndGgobWlzc2luZ19hdHRyKSA+IDApIHsKICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICB9CgogICAgcHJvZmlsZV93aWRlIDwtIHByb2ZpbGVfd2lkZSAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELCBwYXJ0eV9uLCB0YXNrLCBwcm9maWxlLCBjaG9pY2UsIHNlbGVjdGVkLAogICAgICAgIHRhc2tfaWQsIHByb2ZpbGVfaWQsCiAgICAgICAgYWxsX29mKHJlcXVpcmVkX2F0dHJfdmFycykKICAgICAgKSAlPiUKICAgICAgYXJyYW5nZShJRCwgdGFzaywgcHJvZmlsZSkKCiAgICByZXR1cm4ocHJvZmlsZV93aWRlKQogIH0KCgogIGNvbmpvaW50XzIgPC0gbWFrZV9wcm9maWxlX2xvbmcoZGYsIDIpCiAgY29uam9pbnRfMyA8LSBtYWtlX3Byb2ZpbGVfbG9uZyhkZiwgMykKICBjb25qb2ludF80IDwtIG1ha2VfcHJvZmlsZV9sb25nKGRmLCA0KQogIGNvbmpvaW50XzUgPC0gbWFrZV9wcm9maWxlX2xvbmcoZGYsIDUpCgogIGNvbmpvaW50X2FsbF91bmZpbHRlcmVkIDwtIGJpbmRfcm93cygKICAgIGNvbmpvaW50XzIsCiAgICBjb25qb2ludF8zLAogICAgY29uam9pbnRfNCwKICAgIGNvbmpvaW50XzUKICApCgoKICBpZF90YXNrX2NoZWNrIDwtIGNvbmpvaW50X2FsbF91bmZpbHRlcmVkICU+JQogICAgZ3JvdXBfYnkoSUQsIHBhcnR5X24sIHRhc2spICU+JQogICAgc3VtbWFyaXNlKAogICAgICBuX3Byb2ZpbGVzID0gbigpLAogICAgICBzZWxlY3RlZF9zdW0gPSBzdW0oc2VsZWN0ZWQpLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApICU+JQogICAgZ3JvdXBfYnkoSUQsIHBhcnR5X24pICU+JQogICAgc3VtbWFyaXNlKAogICAgICBuX3Rhc2tzID0gbl9kaXN0aW5jdCh0YXNrKSwKICAgICAgYWxsX3Rhc2tzX29rID0gYWxsKG5fcHJvZmlsZXMgPT0gcGFydHlfbiAmIHNlbGVjdGVkX3N1bSA9PSAxKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKQoKICB2YWxpZF9pZHMgPC0gaWRfdGFza19jaGVjayAlPiUKICAgIGZpbHRlcihuX3Rhc2tzID09IDUsIGFsbF90YXNrc19vaykKCiAgY29uam9pbnRfYWxsIDwtIGNvbmpvaW50X2FsbF91bmZpbHRlcmVkICU+JQogICAgc2VtaV9qb2luKHZhbGlkX2lkcywgYnkgPSBjKCJJRCIsICJwYXJ0eV9uIikpCgogIG5fYnlfcGFydHkgPC0gdmFsaWRfaWRzICU+JQogICAgY291bnQocGFydHlfbiwgbmFtZSA9ICJuIikgJT4lCiAgICBjb21wbGV0ZShwYXJ0eV9uID0gMjo1LCBmaWxsID0gbGlzdChuID0gMCkpICU+JQogICAgYXJyYW5nZShwYXJ0eV9uKQoKICBuX3RvdGFsIDwtIHZhbGlkX2lkcyAlPiUKICAgIHN1bW1hcmlzZShuID0gbl9kaXN0aW5jdChJRCkpICU+JQogICAgcHVsbChuKQoKICBmaWd1cmVfbl9sYWJlbHMgPC0gYmluZF9yb3dzKAogICAgdGliYmxlKAogICAgICBwb3NpdGlvbiA9ICLlhajjgrXjg7Pjg5fjg6siLAogICAgICBsYWJlbCA9IHBhc3RlMCgi5YWo44K144Oz44OX44OrLCBuPSIsIHNjYWxlczo6Y29tbWEobl90b3RhbCkpCiAgICApLAogICAgbl9ieV9wYXJ0eSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIHBvc2l0aW9uID0gcGFzdGUwKHBhcnR5X24sICLmlL/lhZrpgbjmip4iKSwKICAgICAgICBsYWJlbCA9IHBhc3RlMCgibj0iLCBzY2FsZXM6OmNvbW1hKG4pKQogICAgICApICU+JQogICAgICBzZWxlY3QocG9zaXRpb24sIGxhYmVsKQogICkKCiAgY2F0KCJcbuWIhuaekOWvvuixoeiAheaVsFxuIikKICBwcmludChuX2J5X3BhcnR5KQogIGNhdCgi5YWo44K144Oz44OX44OrIG49Iiwgbl90b3RhbCwgIlxuIiwgc2VwID0gIiIpCgogIHdyaXRlX2Nzdl9zYWZlbHkoaWRfdGFza19jaGVjaywgImlkX3Rhc2tfY2hlY2suY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KHZhbGlkX2lkcywgInZhbGlkX2lkcy5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkobl9ieV9wYXJ0eSwgIm5fYnlfcGFydHkuY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KGZpZ3VyZV9uX2xhYmVscywgImZpZ3VyZV9uX2xhYmVscy5jc3YiKQoKCiAgY2hlY2tfcHJvZmlsZSA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBncm91cF9ieShwYXJ0eV9uLCBJRCwgdGFzaywgdGFza19pZCkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG5fcHJvZmlsZXMgPSBuKCksCiAgICAgIHNlbGVjdGVkX3N1bSA9IHN1bShzZWxlY3RlZCksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkgJT4lCiAgICBjb3VudChwYXJ0eV9uLCBuX3Byb2ZpbGVzLCBzZWxlY3RlZF9zdW0pCgogIHByaW50KGNoZWNrX3Byb2ZpbGUpCgogIHN0b3BpZm5vdChhbGwoY2hlY2tfcHJvZmlsZSRuX3Byb2ZpbGVzID09IGNoZWNrX3Byb2ZpbGUkcGFydHlfbikpCiAgc3RvcGlmbm90KGFsbChjaGVja19wcm9maWxlJHNlbGVjdGVkX3N1bSA9PSAxKSkKCiAgYWxsb3dlZF9kZiA8LSBlbmZyYW1lKGFsbG93ZWRfbGV2ZWxzLCBuYW1lID0gIm5hbWUiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQogICAgdW5uZXN0KHZhbHVlKQoKICB1bmV4cGVjdGVkX3ZhbHVlcyA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBzZWxlY3QoYWxsX29mKHJlcXVpcmVkX2F0dHJfdmFycykpICU+JQogICAgcGl2b3RfbG9uZ2VyKAogICAgICBjb2xzID0gZXZlcnl0aGluZygpLAogICAgICBuYW1lc190byA9ICJuYW1lIiwKICAgICAgdmFsdWVzX3RvID0gInZhbHVlIgogICAgKSAlPiUKICAgIGZpbHRlcighaXMubmEodmFsdWUpLCB2YWx1ZSAhPSAiIikgJT4lCiAgICBkaXN0aW5jdChuYW1lLCB2YWx1ZSkgJT4lCiAgICBhbnRpX2pvaW4oYWxsb3dlZF9kZiwgYnkgPSBjKCJuYW1lIiwgInZhbHVlIikpCgogIHByaW50KHVuZXhwZWN0ZWRfdmFsdWVzKQogIHN0b3BpZm5vdChucm93KHVuZXhwZWN0ZWRfdmFsdWVzKSA9PSAwKQoKICBvYnNlcnZlZF9sZXZlbHMgPC0gY29uam9pbnRfYWxsICU+JQogICAgc2VsZWN0KGFsbF9vZihyZXF1aXJlZF9hdHRyX3ZhcnMpKSAlPiUKICAgIHBpdm90X2xvbmdlcigKICAgICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwKICAgICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwKICAgICAgdmFsdWVzX3RvID0gImxldmVsIgogICAgKSAlPiUKICAgIGRpc3RpbmN0KGF0dHJpYnV0ZSwgbGV2ZWwpICU+JQogICAgYXJyYW5nZShhdHRyaWJ1dGUsIGxldmVsKQoKICB3cml0ZV9jc3Zfc2FmZWx5KGNoZWNrX3Byb2ZpbGUsICJwcm9maWxlX2V4cGFuc2lvbl9jaGVjay5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkob2JzZXJ2ZWRfbGV2ZWxzLCAib2JzZXJ2ZWRfYXR0cmlidXRlX2xldmVscy5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkoY29uam9pbnRfYWxsLCAic3R1ZHkyX3Byb2ZpbGVfbGV2ZWxfZGF0YS5jc3YiKQoKCiAgYW5hbHlzaXNfaWRzIDwtIHZhbGlkX2lkcyAlPiUKICAgIHNlbGVjdChJRCwgcGFydHlfbikKCiAgYXR0ZW50aW9uX3N1bW1hcnkgPC0gZGYgJT4lCiAgICBzZW1pX2pvaW4oYW5hbHlzaXNfaWRzLCBieSA9ICJJRCIpICU+JQogICAgdHJhbnNtdXRlKAogICAgICBJRCwKICAgICAgYXR0ZW50aW9uX3Jlc3BvbnNlID0gbm9ybV90ZXh0KC5kYXRhW1thdHRlbnRpb25fY2hlY2tfdmFyXV0pLAogICAgICBhdHRlbnRpb25fcGFzcyA9IGlzX3Jlc3BvbnNlX2NvZGUoCiAgICAgICAgLmRhdGFbW2F0dGVudGlvbl9jaGVja192YXJdXSwKICAgICAgICBhdHRlbnRpb25fY2hlY2tfY29ycmVjdAogICAgICApCiAgICApICU+JQogICAgY291bnQoYXR0ZW50aW9uX3Jlc3BvbnNlLCBhdHRlbnRpb25fcGFzcywgbmFtZSA9ICJuIikgJT4lCiAgICBhcnJhbmdlKGRlc2MoYXR0ZW50aW9uX3Bhc3MpLCBhdHRlbnRpb25fcmVzcG9uc2UpCgogIG1hbmlwdWxhdGlvbl9zdW1tYXJ5IDwtIG1hcF9kZnIoMjo1LCBmdW5jdGlvbihuX3BhcnR5KSB7CiAgICBtYW5pcHVsYXRpb25fcm93IDwtIG1hbmlwdWxhdGlvbl9tYXAgJT4lCiAgICAgIGZpbHRlcihwYXJ0eV9uID09IG5fcGFydHkpCgogICAgdiA8LSBtYW5pcHVsYXRpb25fcm93JG1hbmlwdWxhdGlvbl92YXIKICAgIGNvcnJlY3QgPC0gbWFuaXB1bGF0aW9uX3JvdyRjb3JyZWN0X2Fuc3dlcgoKICAgIGRmICU+JQogICAgICBzZW1pX2pvaW4oCiAgICAgICAgYW5hbHlzaXNfaWRzICU+JSBmaWx0ZXIocGFydHlfbiA9PSBuX3BhcnR5KSwKICAgICAgICBieSA9ICJJRCIKICAgICAgKSAlPiUKICAgICAgdHJhbnNtdXRlKAogICAgICAgIHBhcnR5X24gPSBuX3BhcnR5LAogICAgICAgIHJlc3BvbnNlID0gbm9ybV90ZXh0KC5kYXRhW1t2XV0pLAogICAgICAgIGNvcnJlY3QgPSBpc19yZXNwb25zZV9jb2RlKC5kYXRhW1t2XV0sIGNvcnJlY3QpCiAgICAgICkgJT4lCiAgICAgIGNvdW50KHBhcnR5X24sIHJlc3BvbnNlLCBjb3JyZWN0LCBuYW1lID0gIm4iKQogIH0pCgogIHdyaXRlX2Nzdl9zYWZlbHkoYXR0ZW50aW9uX3N1bW1hcnksICJhdHRlbnRpb25fY2hlY2tfc3VtbWFyeS5jc3YiKQogIHdyaXRlX2Nzdl9zYWZlbHkobWFuaXB1bGF0aW9uX3N1bW1hcnksICJwYXJ0eV9udW1iZXJfY2hlY2tfc3VtbWFyeS5jc3YiKQoKCiAgY29uam9pbnRfYWxsX20gPC0gY29uam9pbnRfYWxsICU+JQogICAgbXV0YXRlKAogICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoc2VsZWN0ZWQpLAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCgogICAgICBwb2xpY3lfcG9zaXRpb24gPSBmYWN0b3IoCiAgICAgICAgcG9saWN5X3Bvc2l0aW9uLAogICAgICAgIGxldmVscyA9IGMoIuS4remBkyIsICLlj7PmtL7jg7vkv53lrojnmoQiLCAi5bem5rS+44O76Z2p5paw55qEIikKICAgICAgKSwKCiAgICAgIGdvdmVybm1lbnRfc3RhdHVzID0gZmFjdG9yKAogICAgICAgIGdvdmVybm1lbnRfc3RhdHVzLAogICAgICAgIGxldmVscyA9IGMoIumHjuWFmiIsICLkuI7lhZoiKQogICAgICApLAoKICAgICAgZ2RwX2dyb3d0aCA9IGZhY3RvcigKICAgICAgICBnZHBfZ3Jvd3RoLAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAiR0RQ5oiQ6ZW3546HwrEw77yFIiwKICAgICAgICAgICJHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICAgICAgICJHRFDmiJDplbfnjofjg57jgqTjg4rjgrkx77yFIgogICAgICAgICkKICAgICAgKSwKCiAgICAgIG5pa2tlaSA9IGZhY3RvcigKICAgICAgICBuaWtrZWksCiAgICAgICAgbGV2ZWxzID0gYygKICAgICAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiLAogICAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODl+ODqeOCuTEwMDDlhoYiLAogICAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODnuOCpOODiuOCuTEwMDDlhoYiCiAgICAgICAgKQogICAgICApLAoKICAgICAgc2VhdHMgPSBmYWN0b3IoCiAgICAgICAgc2VhdHMsCiAgICAgICAgbGV2ZWxzID0gYygiMTDku6XkuIsiLCAiMTB+NDkiLCAiNTB+OTkiLCAiMTAwfjE5OSIsICIyMDDku6XkuIoiKQogICAgICApLAoKICAgICAgY3BpID0gZmFjdG9yKAogICAgICAgIGNwaSwKICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIsCiAgICAgICAgICAiQ1BJ5YmN5pyf5q+U44OX44Op44K5MeODneOCpOODs+ODiCIsCiAgICAgICAgICAiQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIKICAgICAgICApCiAgICAgICksCgogICAgICB1bmVtcGxveW1lbnQgPSBmYWN0b3IoCiAgICAgICAgdW5lbXBsb3ltZW50LAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAi5aSx5qWt546H5YmN5pyf5q+UwrEw77yFIiwKICAgICAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg5fjg6njgrkx77yFIiwKICAgICAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg57jgqTjg4rjgrkx77yFIgogICAgICAgICkKICAgICAgKSwKCiAgICAgIHBhcnR5X25fZiA9IGZhY3RvcigKICAgICAgICBhcy5jaGFyYWN0ZXIocGFydHlfbiksCiAgICAgICAgbGV2ZWxzID0gYygiMiIsICIzIiwgIjQiLCAiNSIpCiAgICAgICkKICAgICkKCiAgYXR0cl90ZXJtcyA8LSBjKAogICAgInBvbGljeV9wb3NpdGlvbiIsCiAgICAiZ292ZXJubWVudF9zdGF0dXMiLAogICAgImdkcF9ncm93dGgiLAogICAgIm5pa2tlaSIsCiAgICAic2VhdHMiLAogICAgImNwaSIsCiAgICAidW5lbXBsb3ltZW50IgogICkKCgogIGZvcm11bGFfbm9jb3YgPC0gYXMuZm9ybXVsYSgKICAgIHBhc3RlKCJzZWxlY3RlZCB+IiwgcGFzdGUoYXR0cl90ZXJtcywgY29sbGFwc2UgPSAiICsgIikpCiAgKQoKICBydW5fYW1jZV9ub2NvdiA8LSBmdW5jdGlvbihkYXQpIHsKICAgIGZlb2xzKAogICAgICBmb3JtdWxhX25vY292LAogICAgICBkYXRhID0gZGF0LAogICAgICB2Y292ID0gfiBJRAogICAgKQogIH0KCiAgbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YgPC0gY29uam9pbnRfYWxsX20gJT4lCiAgICBzcGxpdCguJHBhcnR5X24pICU+JQogICAgbWFwKHJ1bl9hbWNlX25vY292KQoKICBjYXB0dXJlLm91dHB1dCgKICAgIGV0YWJsZShtb2RlbHNfYnlfcGFydHlfbl9ub2NvdiksCiAgICBmaWxlID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJhbWNlX25vY292X21vZGVscy50eHQiKQogICkKCgogIG1faW50ZXJhY3Rpb24gPC0gZmVvbHMoCiAgICBzZWxlY3RlZCB+CiAgICAgIHBhcnR5X25fZiAqCiAgICAgICgKICAgICAgICBwb2xpY3lfcG9zaXRpb24gKwogICAgICAgICAgZ292ZXJubWVudF9zdGF0dXMgKwogICAgICAgICAgZ2RwX2dyb3d0aCArCiAgICAgICAgICBuaWtrZWkgKwogICAgICAgICAgc2VhdHMgKwogICAgICAgICAgY3BpICsKICAgICAgICAgIHVuZW1wbG95bWVudAogICAgICApLAogICAgZGF0YSA9IGNvbmpvaW50X2FsbF9tLAogICAgdmNvdiA9IH4gSUQKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc3VtbWFyeShtX2ludGVyYWN0aW9uKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgImFtY2VfaW50ZXJhY3Rpb25fbW9kZWwudHh0IikKICApCgoKICB0aWR5X2ZpeGVzdCA8LSBmdW5jdGlvbihtb2RlbCkgewogICAgY3QgPC0gYXMuZGF0YS5mcmFtZShmaXhlc3Q6OmNvZWZ0YWJsZShtb2RlbCkpCiAgICBjdCR0ZXJtIDwtIHJvd25hbWVzKGN0KQoKICAgIGN0ICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgcmVuYW1lKAogICAgICAgIGVzdGltYXRlID0gRXN0aW1hdGUsCiAgICAgICAgc3RkLmVycm9yID0gYFN0ZC4gRXJyb3JgLAogICAgICAgIHN0YXRpc3RpYyA9IGB0IHZhbHVlYCwKICAgICAgICBwLnZhbHVlID0gYFByKD58dHwpYAogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgY29uZi5sb3cgPSBlc3RpbWF0ZSAtIDEuOTYgKiBzdGQuZXJyb3IsCiAgICAgICAgY29uZi5oaWdoID0gZXN0aW1hdGUgKyAxLjk2ICogc3RkLmVycm9yCiAgICAgICkgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICB0ZXJtLCBlc3RpbWF0ZSwgc3RkLmVycm9yLCBzdGF0aXN0aWMsIHAudmFsdWUsCiAgICAgICAgY29uZi5sb3csIGNvbmYuaGlnaAogICAgICApCiAgfQoKICB0ZXJtX2xhYmVscyA8LSB0cmliYmxlKAogICAgfnRlcm0sIH5hdHRyaWJ1dGUsIH5jdWVfdHlwZSwgfmxhYmVsLCB+b3JkZXIsCgogICAgImdvdmVybm1lbnRfc3RhdHVz5LiO5YWaIiwKICAgICLkuI7lhZrvvI/ph47lhZoiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuS4juWFmiIsIDEsCgogICAgInBvbGljeV9wb3NpdGlvbuWPs+a0vuODu+S/neWuiOeahCIsCiAgICAi5pS/562W5L2N572uIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLlj7PmtL7jg7vkv53lrojnmoQiLCAyLAoKICAgICJwb2xpY3lfcG9zaXRpb27lt6bmtL7jg7vpnanmlrDnmoQiLAogICAgIuaUv+etluS9jee9riIsICLmlL/lhZrjga7miYvjgYzjgYvjgooiLCAi5bem5rS+44O76Z2p5paw55qEIiwgMywKCiAgICAic2VhdHMxMH40OSIsCiAgICAi6K2w5bit5pWwIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLorbDluK3mlbDvvJoxMO+9njQ5IiwgNCwKCiAgICAic2VhdHM1MH45OSIsCiAgICAi6K2w5bit5pWwIiwgIuaUv+WFmuOBruaJi+OBjOOBi+OCiiIsICLorbDluK3mlbDvvJo1MO+9njk5IiwgNSwKCiAgICAic2VhdHMxMDB+MTk5IiwKICAgICLorbDluK3mlbAiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuitsOW4reaVsO+8mjEwMO+9njE5OSIsIDYsCgogICAgInNlYXRzMjAw5Lul5LiKIiwKICAgICLorbDluK3mlbAiLCAi5pS/5YWa44Gu5omL44GM44GL44KKIiwgIuitsOW4reaVsO+8mjIwMOS7peS4iiIsIDcsCgogICAgImdkcF9ncm93dGhHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICJHRFDmiJDplbfnjociLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIkdEUO+8muODl+ODqeOCuTHvvIUiLCA4LAoKICAgICJnZHBfZ3Jvd3RoR0RQ5oiQ6ZW3546H44Oe44Kk44OK44K5Me+8hSIsCiAgICAiR0RQ5oiQ6ZW3546HIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICJHRFDvvJrjg57jgqTjg4rjgrkx77yFIiwgOSwKCiAgICAibmlra2Vp5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44OX44Op44K5MTAwMOWGhiIsCiAgICAi5pel57WM5bmz5Z2HIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICLml6XntYzlubPlnYfvvJrjg5fjg6njgrkxMDAw5YaGIiwgMTAsCgogICAgIm5pa2tlaeaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODnuOCpOODiuOCuTEwMDDlhoYiLAogICAgIuaXpee1jOW5s+WdhyIsICLntYzmuIjjga7miYvjgYzjgYvjgooiLCAi5pel57WM5bmz5Z2H77ya44Oe44Kk44OK44K5MTAwMOWGhiIsIDExLAoKICAgICJjcGlDUEnliY3mnJ/mr5Tjg5fjg6njgrkx44Od44Kk44Oz44OIIiwKICAgICJDUEkiLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIkNQSe+8muODl+ODqeOCuTHjg53jgqTjg7Pjg4giLCAxMiwKCiAgICAiY3BpQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIsCiAgICAiQ1BJIiwgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsICJDUEnvvJrjg57jgqTjg4rjgrkx44Od44Kk44Oz44OIIiwgMTMsCgogICAgInVuZW1wbG95bWVudOWksealreeOh+WJjeacn+avlOODl+ODqeOCuTHvvIUiLAogICAgIuWksealreeOhyIsICLntYzmuIjjga7miYvjgYzjgYvjgooiLCAi5aSx5qWt546H77ya44OX44Op44K5Me+8hSIsIDE0LAoKICAgICJ1bmVtcGxveW1lbnTlpLHmpa3njofliY3mnJ/mr5Tjg57jgqTjg4rjgrkx77yFIiwKICAgICLlpLHmpa3njociLCAi57WM5riI44Gu5omL44GM44GL44KKIiwgIuWksealreeOh++8muODnuOCpOODiuOCuTHvvIUiLCAxNQogICkKCiAgYXR0cmlidXRlX29yZGVyIDwtIGMoCiAgICAi5LiO5YWa77yP6YeO5YWaIiwKICAgICLmlL/nrZbkvY3nva4iLAogICAgIuitsOW4reaVsCIsCiAgICAiR0RQ5oiQ6ZW3546HIiwKICAgICLml6XntYzlubPlnYciLAogICAgIkNQSSIsCiAgICAi5aSx5qWt546HIgogICkKCiAgbGFiZWxfb3JkZXIgPC0gdGVybV9sYWJlbHMgJT4lCiAgICBhcnJhbmdlKG9yZGVyKSAlPiUKICAgIHB1bGwobGFiZWwpCgogIG1ha2VfYW1jZV9wbG90X2RmIDwtIGZ1bmN0aW9uKG1vZGVscykgewogICAgaW1hcF9kZnIoCiAgICAgIG1vZGVscywKICAgICAgfiB0aWR5X2ZpeGVzdCgueCkgJT4lCiAgICAgICAgbXV0YXRlKHBhcnR5X24gPSBhcy5jaGFyYWN0ZXIoLnkpKQogICAgKSAlPiUKICAgICAgbGVmdF9qb2luKHRlcm1fbGFiZWxzLCBieSA9ICJ0ZXJtIikgJT4lCiAgICAgIGZpbHRlcighaXMubmEoYXR0cmlidXRlKSkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBlc3RpbWF0ZV9wcCA9IGVzdGltYXRlICogMTAwLAogICAgICAgIGNvbmYubG93X3BwID0gY29uZi5sb3cgKiAxMDAsCiAgICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICAgIHBhcnR5X24gPSBmYWN0b3IoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgbGV2ZWxzID0gYygiMiIsICIzIiwgIjQiLCAiNSIpLAogICAgICAgICAgbGFiZWxzID0gYygiMuaUv+WFmiIsICIz5pS/5YWaIiwgIjTmlL/lhZoiLCAiNeaUv+WFmiIpCiAgICAgICAgKSwKICAgICAgICBhdHRyaWJ1dGUgPSBmYWN0b3IoYXR0cmlidXRlLCBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIpLAogICAgICAgIGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSByZXYobGFiZWxfb3JkZXIpKQogICAgICApCiAgfQoKICBhbWNlX3Bsb3Rfbm9jb3YgPC0gbWFrZV9hbWNlX3Bsb3RfZGYobW9kZWxzX2J5X3BhcnR5X25fbm9jb3YpCiAgd3JpdGVfY3N2X3NhZmVseShhbWNlX3Bsb3Rfbm9jb3YsICJhbWNlX25vY292X2NvZWZmaWNpZW50cy5jc3YiKQoKICBpbnRlcmFjdGlvbl9wbG90X2RmIDwtIHRpZHlfZml4ZXN0KG1faW50ZXJhY3Rpb24pICU+JQogICAgZmlsdGVyKHN0cl9kZXRlY3QodGVybSwgInBhcnR5X25fZlszNDVdIikpICU+JQogICAgbXV0YXRlKAogICAgICBwYXJ0eV9uX2NvZGUgPSBzdHJfZXh0cmFjdCh0ZXJtLCAicGFydHlfbl9mWzM0NV0iKSwKICAgICAgcGFydHlfbiA9IHN0cl9yZW1vdmUocGFydHlfbl9jb2RlLCAicGFydHlfbl9mIiksCiAgICAgIGJhc2VfdGVybSA9IHRlcm0gJT4lCiAgICAgICAgc3RyX3JlbW92ZSgicGFydHlfbl9mWzM0NV06IikgJT4lCiAgICAgICAgc3RyX3JlbW92ZSgiOnBhcnR5X25fZlszNDVdIikKICAgICkgJT4lCiAgICBsZWZ0X2pvaW4odGVybV9sYWJlbHMsIGJ5ID0gYygiYmFzZV90ZXJtIiA9ICJ0ZXJtIikpICU+JQogICAgZmlsdGVyKCFpcy5uYShhdHRyaWJ1dGUpKSAlPiUKICAgIG11dGF0ZSgKICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICBwYXJ0eV9uX2xhYmVsID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gYygiMyIsICI0IiwgIjUiKSwKICAgICAgICBsYWJlbHMgPSBjKCIz5pS/5YWaIiwgIjTmlL/lhZoiLCAiNeaUv+WFmiIpCiAgICAgICksCiAgICAgIGF0dHJpYnV0ZSA9IGZhY3RvcihhdHRyaWJ1dGUsIGxldmVscyA9IGF0dHJpYnV0ZV9vcmRlciksCiAgICAgIGxhYmVsID0gZmFjdG9yKGxhYmVsLCBsZXZlbHMgPSByZXYobGFiZWxfb3JkZXIpKQogICAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KGludGVyYWN0aW9uX3Bsb3RfZGYsICJhbWNlX2ludGVyYWN0aW9uX2NvZWZmaWNpZW50cy5jc3YiKQoKCiAgcmVjb2RlX2ZlbWFsZV9zdHVkeTIgPC0gZnVuY3Rpb24oeCkgewogICAgeF9udW0gPC0gYXNfbnVtKHgpCgogICAgY2FzZV93aGVuKAogICAgICB4X251bSA9PSAyIH4gMUwsCiAgICAgIHhfbnVtID09IDEgfiAwTCwKICAgICAgVFJVRSB+IE5BX2ludGVnZXJfCiAgICApCiAgfQoKICByZWNvZGVfY29sbGVnZV9ncmFkX3N0dWR5MiA8LSBmdW5jdGlvbih4KSB7CiAgICB4X251bSA8LSBhc19udW0oeCkKCiAgICBjYXNlX3doZW4oCiAgICAgIHhfbnVtICVpbiUgYyg0LCA1KSB+IDFMLAogICAgICB4X251bSAlaW4lIGMoMSwgMiwgMykgfiAwTCwKICAgICAgVFJVRSB+IE5BX2ludGVnZXJfCiAgICApCiAgfQoKICByZWNvZGVfcGFydHlfc3VwcG9ydF9zdHVkeTIgPC0gZnVuY3Rpb24oeCkgewogICAgeF9udW0gPC0gYXNfbnVtKHgpCgogICAgY2FzZV93aGVuKAogICAgICB4X251bSA9PSAxIH4gIuiHqueUseawkeS4u+WFmiIsCiAgICAgIHhfbnVtID09IDIgfiAi5Lit6YGT5pS56Z2p6YCj5ZCIIiwKICAgICAgeF9udW0gPT0gMyB+ICLnq4vmhrLmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSA0IH4gIuWFrOaYjuWFmiIsCiAgICAgIHhfbnVtID09IDUgfiAi5pel5pys57at5paw44Gu5LyaIiwKICAgICAgeF9udW0gPT0gNiB+ICLlm73msJHmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSA3IH4gIuOCjOOBhOOCj+aWsOmBuOe1hCIsCiAgICAgIHhfbnVtID09IDggfiAi5pel5pys5YWx55Sj5YWaIiwKICAgICAgeF9udW0gPT0gOSB+ICLlj4LmlL/lhZoiLAogICAgICB4X251bSA9PSAxMCB+ICLml6XmnKzkv53lrojlhZoiLAogICAgICB4X251bSA9PSAxMSB+ICLnpL7kvJrmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSAxMiB+ICLjg4Hjg7zjg6Djgb/jgonjgYQiLAogICAgICB4X251bSA9PSAxMyB+ICLjgZ3jga7ku5YiLAogICAgICB4X251bSA9PSAxNCB+ICLmlK/mjIHmlL/lhZrjgarjgZciLAogICAgICB4X251bSA9PSAxNSB+ICLjgo/jgYvjgonjgarjgYQiLAogICAgICB4X251bSA9PSAxNiB+ICLnrZTjgYjjgZ/jgY/jgarjgYQiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogIH0KCiAgZ2VuZGVyX3JhdyA8LSBnZXRfdmFyKGRmLCBjKCJRMi4xIiwgIlEyXzEiKSkKICBhZ2VfcmF3IDwtIGdldF92YXIoZGYsIGMoIlEyLjJfMiIsICJRMi4yLjIiLCAiUTJfMl8yIikpCiAgZWR1Y2F0aW9uX3JhdyA8LSBnZXRfdmFyKGRmLCBjKCJRMi4zIiwgIlEyXzMiKSkKICBpbmNvbWVfZ3Jvc3NfcmF3IDwtIGdldF92YXIoZGYsIGMoIlEyLjVfMSIsICJRMi41LjEiLCAiUTJfNV8xIikpCiAgaW5jb21lX25ldF9yYXcgPC0gZ2V0X3ZhcihkZiwgYygiUTIuNV8yIiwgIlEyLjUuMiIsICJRMl81XzIiKSkKICBwYXJ0eV9zdXBwb3J0X3JhdyA8LSBnZXRfdmFyKGRmLCBjKCJROC4yIiwgIlE4XzIiKSkKCiAgY292YXJfaWQgPC0gZGYgJT4lCiAgICB0cmFuc211dGUoCiAgICAgIElEID0gYXMuY2hhcmFjdGVyKFJlc3BvbnNlSWQpLAogICAgICBmZW1hbGUgPSByZWNvZGVfZmVtYWxlX3N0dWR5MihnZW5kZXJfcmF3KSwKICAgICAgYWdlID0gYXNfbnVtKGFnZV9yYXcpLAogICAgICBjb2xsZWdlX2dyYWQgPSByZWNvZGVfY29sbGVnZV9ncmFkX3N0dWR5MihlZHVjYXRpb25fcmF3KSwKICAgICAgaW5jb21lX2dyb3NzID0gYXNfbnVtKGluY29tZV9ncm9zc19yYXcpLAogICAgICBpbmNvbWVfbmV0ID0gYXNfbnVtKGluY29tZV9uZXRfcmF3KSwKICAgICAgaW5jb21lX2dyb3NzX2xvZyA9IGxvZzFwKGluY29tZV9ncm9zcyksCiAgICAgIGluY29tZV9uZXRfbG9nID0gbG9nMXAoaW5jb21lX25ldCksCiAgICAgIHBhcnR5X3N1cHBvcnQgPSByZWNvZGVfcGFydHlfc3VwcG9ydF9zdHVkeTIocGFydHlfc3VwcG9ydF9yYXcpLAogICAgICBwYXJ0eV9zdXBwb3J0X2YgPSBmYWN0b3JfbWlzcyhwYXJ0eV9zdXBwb3J0KQogICAgKSAlPiUKICAgIHNlbWlfam9pbih2YWxpZF9pZHMgJT4lIHNlbGVjdChJRCksIGJ5ID0gIklEIikgJT4lCiAgICBkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKCiAgY292YXJfaWQgPC0gY292YXJfaWQgJT4lCiAgICBtdXRhdGUoCiAgICAgIGFnZSA9IGlmX2Vsc2UoYWdlID49IDE4ICYgYWdlIDw9IDc5LCBhZ2UsIE5BX3JlYWxfKQogICAgKQoKICBhZ2VfaW1wX29iaiA8LSBtZWFuX2ltcHV0ZShjb3Zhcl9pZCRhZ2UpCiAgaW5jb21lX2dyb3NzX2ltcF9vYmogPC0gbWVhbl9pbXB1dGUoY292YXJfaWQkaW5jb21lX2dyb3NzX2xvZykKCiAgY292YXJfaWQgPC0gY292YXJfaWQgJT4lCiAgICBtdXRhdGUoCiAgICAgIGZlbWFsZV9pbXAgPSBpZl9lbHNlKGlzLm5hKGZlbWFsZSksIDBMLCBmZW1hbGUpLAogICAgICBmZW1hbGVfbWlzcyA9IGFzLmludGVnZXIoaXMubmEoZmVtYWxlKSksCgogICAgICBjb2xsZWdlX2dyYWRfaW1wID0gaWZfZWxzZShpcy5uYShjb2xsZWdlX2dyYWQpLCAwTCwgY29sbGVnZV9ncmFkKSwKICAgICAgY29sbGVnZV9ncmFkX21pc3MgPSBhcy5pbnRlZ2VyKGlzLm5hKGNvbGxlZ2VfZ3JhZCkpLAoKICAgICAgYWdlX2ltcCA9IGFnZV9pbXBfb2JqJHZhbHVlLAogICAgICBhZ2VfbWlzcyA9IGFnZV9pbXBfb2JqJG1pc3MsCgogICAgICBpbmNvbWVfZ3Jvc3NfbG9nX2ltcCA9IGluY29tZV9ncm9zc19pbXBfb2JqJHZhbHVlLAogICAgICBpbmNvbWVfZ3Jvc3NfbG9nX21pc3MgPSBpbmNvbWVfZ3Jvc3NfaW1wX29iaiRtaXNzCiAgICApCgogIGNvdmFyaWF0ZV9taXNzaW5nX3N1bW1hcnkgPC0gY292YXJfaWQgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG5faWRzID0gbl9kaXN0aW5jdChJRCksCiAgICAgIGZlbWFsZV9taXNzaW5nID0gc3VtKGlzLm5hKGZlbWFsZSkpLAogICAgICBhZ2VfbWlzc2luZyA9IHN1bShpcy5uYShhZ2UpKSwKICAgICAgY29sbGVnZV9ncmFkX21pc3NpbmcgPSBzdW0oaXMubmEoY29sbGVnZV9ncmFkKSksCiAgICAgIGluY29tZV9ncm9zc19taXNzaW5nID0gc3VtKGlzLm5hKGluY29tZV9ncm9zc19sb2cpKSwKICAgICAgcGFydHlfc3VwcG9ydF9taXNzaW5nID0gc3VtKGlzLm5hKHBhcnR5X3N1cHBvcnQpKQogICAgKQoKICBwcmludChjb3ZhcmlhdGVfbWlzc2luZ19zdW1tYXJ5KQogIHdyaXRlX2Nzdl9zYWZlbHkoY292YXJfaWQsICJyZXNwb25kZW50X2NvdmFyaWF0ZXMuY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KGNvdmFyaWF0ZV9taXNzaW5nX3N1bW1hcnksICJjb3ZhcmlhdGVfbWlzc2luZ19zdW1tYXJ5LmNzdiIpCgoKICBjb25qb2ludF9hbGxfY292IDwtIGNvbmpvaW50X2FsbF9tICU+JQogICAgbGVmdF9qb2luKGNvdmFyX2lkLCBieSA9ICJJRCIpCgogIGNvdmFyaWF0ZV90ZXJtcyA8LSBjKAogICAgImZlbWFsZV9pbXAiLAogICAgImZlbWFsZV9taXNzIiwKICAgICJhZ2VfaW1wIiwKICAgICJhZ2VfbWlzcyIsCiAgICAiY29sbGVnZV9ncmFkX2ltcCIsCiAgICAiY29sbGVnZV9ncmFkX21pc3MiLAogICAgImluY29tZV9ncm9zc19sb2dfaW1wIiwKICAgICJpbmNvbWVfZ3Jvc3NfbG9nX21pc3MiLAogICAgInBhcnR5X3N1cHBvcnRfZiIKICApCgogIGhhc192YXJpYXRpb24gPC0gZnVuY3Rpb24oZGF0LCB2KSB7CiAgICBpZiAoIXYgJWluJSBuYW1lcyhkYXQpKSByZXR1cm4oRkFMU0UpCiAgICBkcGx5cjo6bl9kaXN0aW5jdChkYXRbW3ZdXSwgbmEucm0gPSBUUlVFKSA+IDEKICB9CgogIGNvdmFyaWF0ZV90ZXJtc191c2UgPC0gY292YXJpYXRlX3Rlcm1zWwogICAgbWFwX2xnbChjb3ZhcmlhdGVfdGVybXMsIH4gaGFzX3ZhcmlhdGlvbihjb25qb2ludF9hbGxfY292LCAueCkpCiAgXQoKICBmb3JtdWxhX2NvdiA8LSBhcy5mb3JtdWxhKAogICAgcGFzdGUoCiAgICAgICJzZWxlY3RlZCB+IiwKICAgICAgcGFzdGUoYyhhdHRyX3Rlcm1zLCBjb3ZhcmlhdGVfdGVybXNfdXNlKSwgY29sbGFwc2UgPSAiICsgIikKICAgICkKICApCgogIHJ1bl9hbWNlX2NvdiA8LSBmdW5jdGlvbihkYXQpIHsKICAgIGZlb2xzKAogICAgICBmb3JtdWxhX2NvdiwKICAgICAgZGF0YSA9IGRhdCwKICAgICAgdmNvdiA9IH4gSUQKICAgICkKICB9CgogIG1vZGVsc19ieV9wYXJ0eV9uX2NvdiA8LSBjb25qb2ludF9hbGxfY292ICU+JQogICAgc3BsaXQoLiRwYXJ0eV9uKSAlPiUKICAgIG1hcChydW5fYW1jZV9jb3YpCgogIGNhcHR1cmUub3V0cHV0KAogICAgZXRhYmxlKAogICAgICBtb2RlbHNfYnlfcGFydHlfbl9ub2NvdiwKICAgICAgbW9kZWxzX2J5X3BhcnR5X25fY292LAogICAgICBoZWFkZXJzID0gYygKICAgICAgICByZXAoIuWFseWkiemHj+OBquOBlyIsIGxlbmd0aChtb2RlbHNfYnlfcGFydHlfbl9ub2NvdikpLAogICAgICAgIHJlcCgi5YWx5aSJ6YeP44GC44KKIiwgbGVuZ3RoKG1vZGVsc19ieV9wYXJ0eV9uX2NvdikpCiAgICAgICkKICAgICksCiAgICBmaWxlID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJhbWNlX25vY292X2FuZF9jb3ZfbW9kZWxzLnR4dCIpCiAgKQoKICBhbWNlX3Bsb3RfY292IDwtIG1ha2VfYW1jZV9wbG90X2RmKG1vZGVsc19ieV9wYXJ0eV9uX2NvdikKICB3cml0ZV9jc3Zfc2FmZWx5KGFtY2VfcGxvdF9jb3YsICJhbWNlX2Nvdl9jb2VmZmljaWVudHMuY3N2IikKCgogIHN0dWR5X2xhYmVsIDwtICLlrp/pqJMy77yIMjAyNuW5tO+8iSIKCiAgdGVybV9sYWJlbHNfZmFjZXQgPC0gdGVybV9sYWJlbHMgJT4lCiAgICBtdXRhdGUoCiAgICAgIGF0dHJpYnV0ZV9mYWNldCA9IGF0dHJpYnV0ZQogICAgKQoKICBhdHRyaWJ1dGVfb3JkZXJfZmFjZXQgPC0gYygKICAgICLkuI7lhZrvvI/ph47lhZoiLAogICAgIuaUv+etluS9jee9riIsCiAgICAi6K2w5bit5pWwIiwKICAgICJHRFDmiJDplbfnjociLAogICAgIuaXpee1jOW5s+WdhyIsCiAgICAiQ1BJIiwKICAgICLlpLHmpa3njociCiAgKQoKICBtYWtlX2FtY2VfZmFjZXRfZGYgPC0gZnVuY3Rpb24obW9kZWxzKSB7CiAgICBpbWFwX2RmcigKICAgICAgbW9kZWxzLAogICAgICB+IHRpZHlfZml4ZXN0KC54KSAlPiUKICAgICAgICBtdXRhdGUocGFydHlfbiA9IGFzLmNoYXJhY3RlcigueSkpCiAgICApICU+JQogICAgICBsZWZ0X2pvaW4odGVybV9sYWJlbHNfZmFjZXQsIGJ5ID0gInRlcm0iKSAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShhdHRyaWJ1dGVfZmFjZXQpKSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIGVzdGltYXRlX3BwID0gZXN0aW1hdGUgKiAxMDAsCiAgICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgICBjb25mLmhpZ2hfcHAgPSBjb25mLmhpZ2ggKiAxMDAsCiAgICAgICAgcGFydHlfbiA9IGZhY3RvcigKICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICBsZXZlbHMgPSBjKCIyIiwgIjMiLCAiNCIsICI1IiksCiAgICAgICAgICBsYWJlbHMgPSBjKCIy5pS/5YWaIiwgIjPmlL/lhZoiLCAiNOaUv+WFmiIsICI15pS/5YWaIikKICAgICAgICApLAogICAgICAgIGF0dHJpYnV0ZV9mYWNldCA9IGZhY3RvcigKICAgICAgICAgIGF0dHJpYnV0ZV9mYWNldCwKICAgICAgICAgIGxldmVscyA9IGF0dHJpYnV0ZV9vcmRlcl9mYWNldAogICAgICAgICksCiAgICAgICAgbGFiZWwgPSBmYWN0b3IoCiAgICAgICAgICBsYWJlbCwKICAgICAgICAgIGxldmVscyA9IHJldihsYWJlbF9vcmRlcikKICAgICAgICApCiAgICAgICkKICB9CgogIGFtY2VfcGxvdF9kZl9jb3ZfZmFjZXQgPC0gbWFrZV9hbWNlX2ZhY2V0X2RmKG1vZGVsc19ieV9wYXJ0eV9uX2NvdikKICBhbWNlX3Bsb3RfZGZfbm9jb3ZfZmFjZXQgPC0gbWFrZV9hbWNlX2ZhY2V0X2RmKG1vZGVsc19ieV9wYXJ0eV9uX25vY292KQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgYW1jZV9wbG90X2RmX2Nvdl9mYWNldCwKICAgICJhbWNlX2Nvdl9mYWNldF9jb2VmZmljaWVudHMuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIGFtY2VfcGxvdF9kZl9ub2Nvdl9mYWNldCwKICAgICJhbWNlX25vY292X2ZhY2V0X2NvZWZmaWNpZW50cy5jc3YiCiAgKQoKCiAgcF9hbWNlX2Nvdl9mYWNldCA8LSBnZ3Bsb3QoCiAgICBhbWNlX3Bsb3RfZGZfY292X2ZhY2V0LAogICAgYWVzKAogICAgICB4ID0gZXN0aW1hdGVfcHAsCiAgICAgIHkgPSBsYWJlbCwKICAgICAgc2hhcGUgPSBwYXJ0eV9uLAogICAgICBsaW5ldHlwZSA9IHBhcnR5X24sCiAgICAgIGdyb3VwID0gcGFydHlfbgogICAgKQogICkgKwogICAgZ2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImdyZXkzNSIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcmgoCiAgICAgIGFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIGhlaWdodCA9IDAuMTYsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX3BvaW50KAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksCiAgICAgIHNpemUgPSAyLjUsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIHN0cm9rZSA9IDAuOAogICAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBhdHRyaWJ1dGVfZmFjZXQgfiAuLAogICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgc3BhY2UgPSAiZnJlZV95IiwKICAgICAgc3dpdGNoID0gInkiCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIgcHAiKSwKICAgICAgYnJlYWtzID0gc2VxKC0xMiwgMTIsIGJ5ID0gMikKICAgICkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKAogICAgICBuYW1lID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLmlL/lhZoiID0gMTYsCiAgICAgICAgIjPmlL/lhZoiID0gMTcsCiAgICAgICAgIjTmlL/lhZoiID0gMTUsCiAgICAgICAgIjXmlL/lhZoiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICLmlL/lhZrmlbDpgbjmip7ogqIiLAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIy5pS/5YWaIiA9ICJzb2xpZCIsCiAgICAgICAgIjPmlL/lhZoiID0gImRhc2hlZCIsCiAgICAgICAgIjTmlL/lhZoiID0gImRvdHRlZCIsCiAgICAgICAgIjXmlL/lhZoiID0gImRvdGRhc2giCiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgeCA9ICLpgbjmip7norrnjofjga7lpInljJYiLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idygKICAgICAgYmFzZV9zaXplID0gMTIsCiAgICAgIGJhc2VfZmFtaWx5ID0gIll1IEdvdGhpYyIKICAgICkgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTYKICAgICAgKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICAgICkKCiAgcHJpbnQocF9hbWNlX2Nvdl9mYWNldCkKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfY292X2ZhY2V0X21vZGVsLnBuZyIsCiAgICBwX2FtY2VfY292X2ZhY2V0LAogICAgd2lkdGggPSAxMC41LAogICAgaGVpZ2h0ID0gOC41CiAgKQoKICBwX2FtY2VfY292X21haW4gPC0gcF9hbWNlX2Nvdl9mYWNldAoKCiAgbWFrZV9oZWF0bWFwX2RmIDwtIGZ1bmN0aW9uKGFtY2VfcGxvdF9kZikgewogICAgaGVhdF9kZiA8LSBhbWNlX3Bsb3RfZGYgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBhYnNfYW1jZSA9IGFicyhlc3RpbWF0ZV9wcCksCiAgICAgICAgY3VlX3R5cGVfY29kZSA9IGNhc2Vfd2hlbigKICAgICAgICAgIGN1ZV90eXBlID09ICLmlL/lhZrjga7miYvjgYzjgYvjgooiIH4gInBhcnR5IiwKICAgICAgICAgIGN1ZV90eXBlID09ICLntYzmuIjjga7miYvjgYzjgYvjgooiIH4gImVjb25vbXkiLAogICAgICAgICAgVFJVRSB+ICJvdGhlciIKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIGdyb3VwX2J5KHBhcnR5X24pICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgcmFua193aXRoaW5fcGFydHkgPSBtaW5fcmFuayhkZXNjKGFic19hbWNlKSksCiAgICAgICAgbl9pbl9jb2wgPSBuKCksCiAgICAgICAgcmFua19zY29yZSA9IGlmX2Vsc2UoCiAgICAgICAgICBuX2luX2NvbCA9PSAxLAogICAgICAgICAgMSwKICAgICAgICAgIDEgLSAocmFua193aXRoaW5fcGFydHkgLSAxKSAvIChuX2luX2NvbCAtIDEpCiAgICAgICAgKQogICAgICApICU+JQogICAgICB1bmdyb3VwKCkKCiAgICByb3dfb3JkZXJfZGYgPC0gaGVhdF9kZiAlPiUKICAgICAgZ3JvdXBfYnkobGFiZWwsIGN1ZV90eXBlX2NvZGUpICU+JQogICAgICBzdW1tYXJpc2UoCiAgICAgICAgbWVhbl9hYnNfYW1jZSA9IG1lYW4oYWJzX2FtY2UsIG5hLnJtID0gVFJVRSksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApICU+JQogICAgICBhcnJhbmdlKGRlc2MobWVhbl9hYnNfYW1jZSkpCgogICAgcm93X2xldmVscyA8LSBhcy5jaGFyYWN0ZXIocm93X29yZGVyX2RmJGxhYmVsKQoKICAgIGhlYXRfZGYgPC0gaGVhdF9kZiAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIGxhYmVsID0gZmFjdG9yKAogICAgICAgICAgYXMuY2hhcmFjdGVyKGxhYmVsKSwKICAgICAgICAgIGxldmVscyA9IHJldihyb3dfbGV2ZWxzKQogICAgICAgICkKICAgICAgKQoKICAgIGxhYmVsX2NvbG9yX21hcCA8LSByb3dfb3JkZXJfZGYgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBsYWJlbF9tYXJrZG93biA9IGNhc2Vfd2hlbigKICAgICAgICAgIGN1ZV90eXBlX2NvZGUgPT0gInBhcnR5IiB+CiAgICAgICAgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAiPHNwYW4gc3R5bGU9J2NvbG9yOiMxMTExMTE7Jz4iLAogICAgICAgICAgICAgIGxhYmVsLAogICAgICAgICAgICAgICI8L3NwYW4+IgogICAgICAgICAgICApLAogICAgICAgICAgY3VlX3R5cGVfY29kZSA9PSAiZWNvbm9teSIgfgogICAgICAgICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgIjxzcGFuIHN0eWxlPSdjb2xvcjojOEE4QThBOyc+IiwKICAgICAgICAgICAgICBsYWJlbCwKICAgICAgICAgICAgICAiPC9zcGFuPiIKICAgICAgICAgICAgKSwKICAgICAgICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIobGFiZWwpCiAgICAgICAgKQogICAgICApCgogICAgbGFiZWxfbWFya2Rvd25fdmVjIDwtIHNldE5hbWVzKAogICAgICBsYWJlbF9jb2xvcl9tYXAkbGFiZWxfbWFya2Rvd24sCiAgICAgIGFzLmNoYXJhY3RlcihsYWJlbF9jb2xvcl9tYXAkbGFiZWwpCiAgICApCgogICAgbGlzdCgKICAgICAgaGVhdF9kZiA9IGhlYXRfZGYsCiAgICAgIGxhYmVsX21hcmtkb3duX3ZlYyA9IGxhYmVsX21hcmtkb3duX3ZlYwogICAgKQogIH0KCiAgcGxvdF9hbWNlX2hlYXRtYXAgPC0gZnVuY3Rpb24oCiAgICAgIGhlYXRfZGYsCiAgICAgIGxhYmVsX21hcmtkb3duX3ZlYywKICAgICAgd2l0aF9yYW5rID0gVFJVRSwKICAgICAgdGl0bGVfdGV4dCA9IE5VTEwpIHsKCiAgICBpZiAod2l0aF9yYW5rKSB7CiAgICAgIGhlYXRfZGYgPC0gaGVhdF9kZiAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBjZWxsX2xhYmVsID0gcGFzdGUwKAogICAgICAgICAgICBzcHJpbnRmKCIlLjFmIiwgZXN0aW1hdGVfcHApLAogICAgICAgICAgICAiXG4oIiwKICAgICAgICAgICAgcmFua193aXRoaW5fcGFydHksCiAgICAgICAgICAgICLkvY0pIgogICAgICAgICAgKQogICAgICAgICkKCiAgICAgIHRleHRfc2l6ZSA8LSAzLjAKICAgICAgbGluZWhlaWdodCA8LSAwLjkKICAgIH0gZWxzZSB7CiAgICAgIGhlYXRfZGYgPC0gaGVhdF9kZiAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBjZWxsX2xhYmVsID0gc3ByaW50ZigiJS4xZiIsIGVzdGltYXRlX3BwKQogICAgICAgICkKCiAgICAgIHRleHRfc2l6ZSA8LSAzLjQKICAgICAgbGluZWhlaWdodCA8LSAxLjAKICAgIH0KCiAgICBnZ3Bsb3QoCiAgICAgIGhlYXRfZGYsCiAgICAgIGFlcygKICAgICAgICB4ID0gcGFydHlfbiwKICAgICAgICB5ID0gbGFiZWwsCiAgICAgICAgZmlsbCA9IHJhbmtfc2NvcmUKICAgICAgKQogICAgKSArCiAgICAgIGdlb21fdGlsZSgKICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICAgICAgbGluZXdpZHRoID0gMC43CiAgICAgICkgKwogICAgICBnZW9tX3RleHQoCiAgICAgICAgYWVzKGxhYmVsID0gY2VsbF9sYWJlbCksCiAgICAgICAgc2l6ZSA9IHRleHRfc2l6ZSwKICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgbGluZWhlaWdodCA9IGxpbmVoZWlnaHQKICAgICAgKSArCiAgICAgIHNjYWxlX3lfZGlzY3JldGUoCiAgICAgICAgbGFiZWxzID0gbGFiZWxfbWFya2Rvd25fdmVjCiAgICAgICkgKwogICAgICBzY2FsZV9maWxsX2dyYWRpZW50KAogICAgICAgIGxvdyA9ICJncmV5OTUiLAogICAgICAgIGhpZ2ggPSAiZ3JleTE1IiwKICAgICAgICBsaW1pdHMgPSBjKDAsIDEpLAogICAgICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMS4wMCksCiAgICAgICAgbGFiZWxzID0gYygi5L2OIiwgIiIsICIiLCAiIiwgIumrmCIpLAogICAgICAgIG5hbWUgPSAi5YiX5YaF6aCG5L2NXG7vvIjmv4PjgYTjgbvjganpq5jkvY3vvIkiCiAgICAgICkgKwogICAgICBsYWJzKAogICAgICAgIHRpdGxlID0gdGl0bGVfdGV4dCwKICAgICAgICB4ID0gIuaUv+WFmuaVsOmBuOaKnuiCoiIsCiAgICAgICAgeSA9IE5VTEwKICAgICAgKSArCiAgICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgICAgIHRoZW1lKAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDkpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICAgICApCiAgfQoKICBoZWF0bWFwX2lucHV0IDwtIG1ha2VfaGVhdG1hcF9kZihhbWNlX3Bsb3RfY292KQoKICBwX2hlYXRfYW1jZV9taXhlZCA8LSBwbG90X2FtY2VfaGVhdG1hcCgKICAgIGhlYXRtYXBfaW5wdXQkaGVhdF9kZiwKICAgIGhlYXRtYXBfaW5wdXQkbGFiZWxfbWFya2Rvd25fdmVjLAogICAgd2l0aF9yYW5rID0gRkFMU0UsCiAgICB0aXRsZV90ZXh0ID0gTlVMTAogICkKCiAgcHJpbnQocF9oZWF0X2FtY2VfbWl4ZWQpCgogIHNhdmVfcGxvdCgKICAgICJhbWNlX2hlYXRtYXBfbWl4ZWRfcmFua19jb2xvcmVkX2xhYmVscy5wbmciLAogICAgcF9oZWF0X2FtY2VfbWl4ZWQsCiAgICB3aWR0aCA9IDguOCwKICAgIGhlaWdodCA9IDguOAogICkKCiAgcF9oZWF0X2FtY2VfbWl4ZWRfcmFua2xhYmVsIDwtIHBsb3RfYW1jZV9oZWF0bWFwKAogICAgaGVhdG1hcF9pbnB1dCRoZWF0X2RmLAogICAgaGVhdG1hcF9pbnB1dCRsYWJlbF9tYXJrZG93bl92ZWMsCiAgICB3aXRoX3JhbmsgPSBUUlVFLAogICAgdGl0bGVfdGV4dCA9IE5VTEwKICApCgogIHByaW50KHBfaGVhdF9hbWNlX21peGVkX3JhbmtsYWJlbCkKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfaGVhdG1hcF9taXhlZF9yYW5rX2NvbG9yZWRfbGFiZWxzX3dpdGhyYW5rLnBuZyIsCiAgICBwX2hlYXRfYW1jZV9taXhlZF9yYW5rbGFiZWwsCiAgICB3aWR0aCA9IDguOCwKICAgIGhlaWdodCA9IDguOAogICkKCiAgcF9oZWF0X2FtY2UgPC0gcF9oZWF0X2FtY2VfbWl4ZWQKICBwX2hlYXRfYW1jZV9yYW5rIDwtIHBfaGVhdF9hbWNlX21peGVkX3JhbmtsYWJlbAoKCiAgcF9hbWNlX2ZhY2V0X25vY292IDwtIGdncGxvdCgKICAgIGFtY2VfcGxvdF9kZl9ub2Nvdl9mYWNldCwKICAgIGFlcygKICAgICAgeCA9IGVzdGltYXRlX3BwLAogICAgICB5ID0gbGFiZWwsCiAgICAgIHNoYXBlID0gcGFydHlfbiwKICAgICAgbGluZXR5cGUgPSBwYXJ0eV9uLAogICAgICBncm91cCA9IHBhcnR5X24KICAgICkKICApICsKICAgIGdlb21fdmxpbmUoCiAgICAgIHhpbnRlcmNlcHQgPSAwLAogICAgICBsaW5ld2lkdGggPSAwLjQ1LAogICAgICBjb2xvciA9ICJncmV5MzUiCiAgICApICsKICAgIGdlb21fZXJyb3JiYXJoKAogICAgICBhZXMoCiAgICAgICAgeG1pbiA9IGNvbmYubG93X3BwLAogICAgICAgIHhtYXggPSBjb25mLmhpZ2hfcHAKICAgICAgKSwKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLAogICAgICBoZWlnaHQgPSAwLjE2LAogICAgICBsaW5ld2lkdGggPSAwLjU1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLAogICAgICBzaXplID0gMi41LAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBzdHJva2UgPSAwLjgKICAgICkgKwogICAgZmFjZXRfZ3JpZCgKICAgICAgYXR0cmlidXRlX2ZhY2V0IH4gLiwKICAgICAgc2NhbGVzID0gImZyZWVfeSIsCiAgICAgIHNwYWNlID0gImZyZWVfeSIsCiAgICAgIHN3aXRjaCA9ICJ5IgogICAgKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiIHBwIiksCiAgICAgIGJyZWFrcyA9IHNlcSgtMTIsIDEyLCBieSA9IDIpCiAgICApICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICLmlL/lhZrmlbDpgbjmip7ogqIiLAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIy5pS/5YWaIiA9IDE2LAogICAgICAgICIz5pS/5YWaIiA9IDE3LAogICAgICAgICI05pS/5YWaIiA9IDE1LAogICAgICAgICI15pS/5YWaIiA9IDEKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAi5pS/5YWa5pWw6YG45oqe6IKiIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMuaUv+WFmiIgPSAic29saWQiLAogICAgICAgICIz5pS/5YWaIiA9ICJkYXNoZWQiLAogICAgICAgICI05pS/5YWaIiA9ICJkb3R0ZWQiLAogICAgICAgICI15pS/5YWaIiA9ICJkb3RkYXNoIgogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHggPSAi6YG45oqe56K6546H44Gu5aSJ5YyWIiwKICAgICAgeSA9IE5VTEwKICAgICkgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTIpICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgc2l6ZSA9IDE2CiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIsCiAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgZmlsbCA9ICJncmV5OTIiLAogICAgICAgIGNvbG9yID0gImdyZXk1NSIKICAgICAgKSwKICAgICAgc3RyaXAudGV4dC55LmxlZnQgPSBlbGVtZW50X3RleHQoCiAgICAgICAgYW5nbGUgPSAwLAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgc2l6ZSA9IDEwCiAgICAgICksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpCiAgICApCgogIHByaW50KHBfYW1jZV9mYWNldF9ub2NvdikKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfZmFjZXRfbm9jb3YucG5nIiwKICAgIHBfYW1jZV9mYWNldF9ub2NvdiwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDkKICApCgogIHBfYW1jZV9ub2Nvdl9hcHBlbmRpeCA8LSBwX2FtY2VfZmFjZXRfbm9jb3YKCgogIHBfaW50ZXJhY3Rpb24gPC0gZ2dwbG90KAogICAgaW50ZXJhY3Rpb25fcGxvdF9kZiwKICAgIGFlcygKICAgICAgeCA9IGVzdGltYXRlX3BwLAogICAgICB5ID0gbGFiZWwsCiAgICAgIHNoYXBlID0gcGFydHlfbl9sYWJlbCwKICAgICAgbGluZXR5cGUgPSBwYXJ0eV9uX2xhYmVsLAogICAgICBncm91cCA9IHBhcnR5X25fbGFiZWwKICAgICkKICApICsKICAgIGdlb21fdmxpbmUoCiAgICAgIHhpbnRlcmNlcHQgPSAwLAogICAgICBsaW5ld2lkdGggPSAwLjQ1LAogICAgICBjb2xvciA9ICJncmV5MzUiCiAgICApICsKICAgIGdlb21fZXJyb3JiYXJoKAogICAgICBhZXMoCiAgICAgICAgeG1pbiA9IGNvbmYubG93X3BwLAogICAgICAgIHhtYXggPSBjb25mLmhpZ2hfcHAKICAgICAgKSwKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLAogICAgICBoZWlnaHQgPSAwLjE2LAogICAgICBsaW5ld2lkdGggPSAwLjU1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLAogICAgICBzaXplID0gMi41LAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBzdHJva2UgPSAwLjgKICAgICkgKwogICAgZmFjZXRfZ3JpZCgKICAgICAgYXR0cmlidXRlIH4gLiwKICAgICAgc2NhbGVzID0gImZyZWVfeSIsCiAgICAgIHNwYWNlID0gImZyZWVfeSIsCiAgICAgIHN3aXRjaCA9ICJ5IgogICAgKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiIHBwIiksCiAgICAgIGJyZWFrcyA9IHNlcSgtOCwgOCwgYnkgPSAyKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAiMuaUv+WFmuOBruWgtOWQiOOBqOOBruavlOi8gyIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjPmlL/lhZoiID0gMTcsCiAgICAgICAgIjTmlL/lhZoiID0gMTUsCiAgICAgICAgIjXmlL/lhZoiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICIy5pS/5YWa44Gu5aC05ZCI44Go44Gu5q+U6LyDIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiM+aUv+WFmiIgPSAiZGFzaGVkIiwKICAgICAgICAiNOaUv+WFmiIgPSAiZG90dGVkIiwKICAgICAgICAiNeaUv+WFmiIgPSAiZG90ZGFzaCIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB4ID0gIjLmlL/lhZrmnaHku7bjgajjga7lt64iLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idyhiYXNlX3NpemUgPSAxMikgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTUKICAgICAgKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICAgICkKCiAgcHJpbnQocF9pbnRlcmFjdGlvbikKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfaW50ZXJhY3Rpb25fZGlmZmVyZW5jZV9mcm9tXzJwYXJ0eS5wbmciLAogICAgcF9pbnRlcmFjdGlvbiwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDkKICApCgoKICBjb25qb2ludF9jbG9naXQgPC0gY29uam9pbnRfYWxsX20gJT4lCiAgICBtdXRhdGUoCiAgICAgIHNlbGVjdGVkID0gYXMuaW50ZWdlcihzZWxlY3RlZCksCiAgICAgIElEID0gYXMuY2hhcmFjdGVyKElEKSwKICAgICAgdGFza19pZCA9IGZhY3Rvcih0YXNrX2lkKSwKICAgICAgcG9saWN5X3Bvc2l0aW9uID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIHBvbGljeV9wb3NpdGlvbiwKICAgICAgICAi5Lit6YGTIgogICAgICApLAogICAgICBnb3Zlcm5tZW50X3N0YXR1cyA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBnb3Zlcm5tZW50X3N0YXR1cywKICAgICAgICAi6YeO5YWaIgogICAgICApLAogICAgICBnZHBfZ3Jvd3RoID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIGdkcF9ncm93dGgsCiAgICAgICAgIkdEUOaIkOmVt+eOh8KxMO+8hSIKICAgICAgKSwKICAgICAgbmlra2VpID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIG5pa2tlaSwKICAgICAgICAi5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U5aSJ44KP44KJ44GaIgogICAgICApLAogICAgICBzZWF0cyA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBzZWF0cywKICAgICAgICAiMTDku6XkuIsiCiAgICAgICksCiAgICAgIGNwaSA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBjcGksCiAgICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIKICAgICAgKSwKICAgICAgdW5lbXBsb3ltZW50ID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIHVuZW1wbG95bWVudCwKICAgICAgICAi5aSx5qWt546H5YmN5pyf5q+UwrEw77yFIgogICAgICApCiAgICApCgogIGZvcm11bGFfY2xvZ2l0X25vY292IDwtIGFzLmZvcm11bGEoCiAgICBwYXN0ZTAoCiAgICAgICJzZWxlY3RlZCB+ICIsCiAgICAgIHBhc3RlKGF0dHJfdGVybXMsIGNvbGxhcHNlID0gIiArICIpLAogICAgICAiICsgc3RyYXRhKHRhc2tfaWQpICsgY2x1c3RlcihJRCkiCiAgICApCiAgKQoKICBydW5fY2xvZ2l0X25vY292IDwtIGZ1bmN0aW9uKGRhdCkgewogICAgc3Vydml2YWw6OmNsb2dpdCgKICAgICAgZm9ybXVsYV9jbG9naXRfbm9jb3YsCiAgICAgIGRhdGEgPSBkYXQsCiAgICAgIG1ldGhvZCA9ICJlZnJvbiIKICAgICkKICB9CgogIG1vZGVsc19jbG9naXRfbm9jb3YgPC0gY29uam9pbnRfY2xvZ2l0ICU+JQogICAgc3BsaXQoLiRwYXJ0eV9uKSAlPiUKICAgIG1hcChydW5fY2xvZ2l0X25vY292KQoKICBjYXB0dXJlLm91dHB1dCgKICAgIGxhcHBseShtb2RlbHNfY2xvZ2l0X25vY292LCBzdW1tYXJ5KSwKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJjb25kaXRpb25hbF9sb2dpdF9tb2RlbHMudHh0IgogICAgKQogICkKCiAgdGlkeV9jbG9naXQgPC0gZnVuY3Rpb24obW9kZWwpIHsKICAgIHMgPC0gc3VtbWFyeShtb2RlbCkKICAgIGN0IDwtIGFzLmRhdGEuZnJhbWUocyRjb2VmZmljaWVudHMpCiAgICBjdCR0ZXJtIDwtIHJvd25hbWVzKGN0KQoKICAgIHNlX2NvbCA8LSBpZiAoInJvYnVzdCBzZSIgJWluJSBuYW1lcyhjdCkpIHsKICAgICAgInJvYnVzdCBzZSIKICAgIH0gZWxzZSBpZiAoInNlKGNvZWYpIiAlaW4lIG5hbWVzKGN0KSkgewogICAgICAic2UoY29lZikiCiAgICB9IGVsc2UgewogICAgICBzdG9wKCJDaGVjayBjbG9naXQiKQogICAgfQoKICAgIHBfY29sIDwtIGlmICgiUHIoPnx6fCkiICVpbiUgbmFtZXMoY3QpKSB7CiAgICAgICJQcig+fHp8KSIKICAgIH0gZWxzZSBpZiAoIlByKD58dHwpIiAlaW4lIG5hbWVzKGN0KSkgewogICAgICAiUHIoPnx0fCkiCiAgICB9IGVsc2UgewogICAgICBOQV9jaGFyYWN0ZXJfCiAgICB9CgogICAgY3QgJT4lCiAgICAgIGFzX3RpYmJsZSgpICU+JQogICAgICB0cmFuc211dGUoCiAgICAgICAgdGVybSA9IHRlcm0sCiAgICAgICAgZXN0aW1hdGUgPSBjb2VmLAogICAgICAgIHN0ZC5lcnJvciA9IC5kYXRhW1tzZV9jb2xdXSwKICAgICAgICBwLnZhbHVlID0gaWYgKCFpcy5uYShwX2NvbCkpIHsKICAgICAgICAgIC5kYXRhW1twX2NvbF1dCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIE5BX3JlYWxfCiAgICAgICAgfSwKICAgICAgICBjb25mLmxvdyA9IGVzdGltYXRlIC0gMS45NiAqIHN0ZC5lcnJvciwKICAgICAgICBjb25mLmhpZ2ggPSBlc3RpbWF0ZSArIDEuOTYgKiBzdGQuZXJyb3IsCiAgICAgICAgb2Rkc19yYXRpbyA9IGV4cChlc3RpbWF0ZSksCiAgICAgICAgb2Rkc19yYXRpb19sb3cgPSBleHAoY29uZi5sb3cpLAogICAgICAgIG9kZHNfcmF0aW9faGlnaCA9IGV4cChjb25mLmhpZ2gpCiAgICAgICkKICB9CgogIGNsb2dpdF9wbG90X2RmIDwtIGltYXBfZGZyKAogICAgbW9kZWxzX2Nsb2dpdF9ub2NvdiwKICAgIH4gdGlkeV9jbG9naXQoLngpICU+JQogICAgICBtdXRhdGUocGFydHlfbiA9IGFzLmNoYXJhY3RlcigueSkpCiAgKSAlPiUKICAgIGxlZnRfam9pbih0ZXJtX2xhYmVscywgYnkgPSAidGVybSIpICU+JQogICAgZmlsdGVyKCFpcy5uYShhdHRyaWJ1dGUpKSAlPiUKICAgIG11dGF0ZSgKICAgICAgcGFydHlfbiA9IGZhY3RvcigKICAgICAgICBwYXJ0eV9uLAogICAgICAgIGxldmVscyA9IGMoIjIiLCAiMyIsICI0IiwgIjUiKSwKICAgICAgICBsYWJlbHMgPSBjKCIy5pS/5YWaIiwgIjPmlL/lhZoiLCAiNOaUv+WFmiIsICI15pS/5YWaIikKICAgICAgKSwKICAgICAgbGFiZWwgPSBmYWN0b3IoCiAgICAgICAgbGFiZWwsCiAgICAgICAgbGV2ZWxzID0gcmV2KGxhYmVsX29yZGVyKQogICAgICApCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBjbG9naXRfcGxvdF9kZiwKICAgICJjb25kaXRpb25hbF9sb2dpdF9jb2VmZmljaWVudHMuY3N2IgogICkKCgogIHBfY2xvZ2l0X29yIDwtIGdncGxvdCgKICAgIGNsb2dpdF9wbG90X2RmLAogICAgYWVzKAogICAgICB4ID0gb2Rkc19yYXRpbywKICAgICAgeSA9IGxhYmVsLAogICAgICBzaGFwZSA9IHBhcnR5X24sCiAgICAgIGxpbmV0eXBlID0gcGFydHlfbiwKICAgICAgZ3JvdXAgPSBwYXJ0eV9uCiAgICApCiAgKSArCiAgICBnZW9tX3ZsaW5lKAogICAgICB4aW50ZXJjZXB0ID0gMSwKICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgbGluZXdpZHRoID0gMC40NSwKICAgICAgY29sb3IgPSAiZ3JleTM1IgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyaCgKICAgICAgYWVzKAogICAgICAgIHhtaW4gPSBvZGRzX3JhdGlvX2xvdywKICAgICAgICB4bWF4ID0gb2Rkc19yYXRpb19oaWdoCiAgICAgICksCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcyKSwKICAgICAgaGVpZ2h0ID0gMC4xNSwKICAgICAgbGluZXdpZHRoID0gMC40NSwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fcG9pbnQoCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcyKSwKICAgICAgc2l6ZSA9IDIuNCwKICAgICAgc3Ryb2tlID0gMC43LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfeF9sb2cxMCgKICAgICAgYnJlYWtzID0gYygKICAgICAgICAwLjYsCiAgICAgICAgMC44LAogICAgICAgIDEuMCwKICAgICAgICAxLjI1LAogICAgICAgIDEuNSwKICAgICAgICAyLjAKICAgICAgKSwKICAgICAgbGFiZWxzID0gYygKICAgICAgICAiMC42IiwKICAgICAgICAiMC44IiwKICAgICAgICAiMS4wIiwKICAgICAgICAiMS4yNSIsCiAgICAgICAgIjEuNSIsCiAgICAgICAgIjIuMCIKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLmlL/lhZoiID0gMTYsCiAgICAgICAgIjPmlL/lhZoiID0gMTcsCiAgICAgICAgIjTmlL/lhZoiID0gMTUsCiAgICAgICAgIjXmlL/lhZoiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMuaUv+WFmiIgPSAic29saWQiLAogICAgICAgICIz5pS/5YWaIiA9ICJkYXNoZWQiLAogICAgICAgICI05pS/5YWaIiA9ICJkb3RkYXNoIiwKICAgICAgICAiNeaUv+WFmiIgPSAidHdvZGFzaCIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB4ID0gIuOCquODg+OCuuavlCIsCiAgICAgIHkgPSBOVUxMLAogICAgICBzaGFwZSA9ICLmlL/lhZrmlbDpgbjmip7ogqIiLAogICAgICBsaW5ldHlwZSA9ICLmlL/lhZrmlbDpgbjmip7ogqIiCiAgICApICsKICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpCiAgICApCgogIHByaW50KHBfY2xvZ2l0X29yKQoKICBzYXZlX3Bsb3QoCiAgICAiY2xvZ2l0X29kZHNyYXRpb19ub2Nvdi5wbmciLAogICAgcF9jbG9naXRfb3IsCiAgICB3aWR0aCA9IDEwLjUsCiAgICBoZWlnaHQgPSA4LjUKICApCgoKICByZWxhdGl2ZV9jdWVfbWFwIDwtIGMoCiAgICBwb2xpY3lfcG9zaXRpb24gPSAicGFydHkiLAogICAgZ292ZXJubWVudF9zdGF0dXMgPSAicGFydHkiLAogICAgc2VhdHMgPSAicGFydHkiLAogICAgZ2RwX2dyb3d0aCA9ICJlY29ub21pYyIsCiAgICBuaWtrZWkgPSAiZWNvbm9taWMiLAogICAgY3BpID0gImVjb25vbWljIiwKICAgIHVuZW1wbG95bWVudCA9ICJlY29ub21pYyIKICApCgogIG1lYW5fYWJzb2x1dGVfcGFpcndpc2VfZGlmZmVyZW5jZSA8LSBmdW5jdGlvbih4KSB7CiAgICB4IDwtIHhbaXMuZmluaXRlKHgpXQoKICAgIGlmIChsZW5ndGgoeCkgPCAyKSB7CiAgICAgIHJldHVybihOQV9yZWFsXykKICAgIH0KCiAgICBwYWlyd2lzZV9kaWZmZXJlbmNlcyA8LSBjb21ibigKICAgICAgeCwKICAgICAgMiwKICAgICAgRlVOID0gZnVuY3Rpb24oeikgYWJzKHpbMV0gLSB6WzJdKQogICAgKQoKICAgIG1lYW4ocGFpcndpc2VfZGlmZmVyZW5jZXMpCiAgfQoKICBsaW5lYXJfc2xvcGUgPC0gZnVuY3Rpb24oeSwgeCkgewogICAga2VlcCA8LSBpcy5maW5pdGUoeSkgJiBpcy5maW5pdGUoeCkKICAgIHkgPC0geVtrZWVwXQogICAgeCA8LSB4W2tlZXBdCgogICAgaWYgKGxlbmd0aCh5KSA8IDIgfHwgbGVuZ3RoKHVuaXF1ZSh4KSkgPCAyKSB7CiAgICAgIHJldHVybihOQV9yZWFsXykKICAgIH0KCiAgICB1bm5hbWUoY29lZihsbSh5IH4geCkpWzJdKQogIH0KCiAgYm9vdHN0cmFwX3R3b19zaWRlZF9wIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0geFtpcy5maW5pdGUoeCldCiAgICBCX3ZhbGlkIDwtIGxlbmd0aCh4KQoKICAgIGlmIChCX3ZhbGlkID09IDApIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHBfbG93ZXIgPC0gKDEgKyBzdW0oeCA8PSAwKSkgLyAoQl92YWxpZCArIDEpCiAgICBwX3VwcGVyIDwtICgxICsgc3VtKHggPj0gMCkpIC8gKEJfdmFsaWQgKyAxKQoKICAgIG1pbigxLCAyICogbWluKHBfbG93ZXIsIHBfdXBwZXIpKQogIH0KCiAgc2FmZV9xdWFudGlsZSA8LSBmdW5jdGlvbih4LCBwcm9iYWJpbGl0eSkgewogICAgeCA8LSB4W2lzLmZpbml0ZSh4KV0KCiAgICBpZiAobGVuZ3RoKHgpID09IDApIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHVubmFtZSgKICAgICAgcXVhbnRpbGUoCiAgICAgICAgeCwKICAgICAgICBwcm9icyA9IHByb2JhYmlsaXR5LAogICAgICAgIHR5cGUgPSA2LAogICAgICAgIG5hLnJtID0gVFJVRQogICAgICApCiAgICApCiAgfQoKICBwcmVwYXJlX3JlbGF0aXZlX2N1ZV9hbmFseXNpcyA8LSBmdW5jdGlvbihkYXRhLCBjdWVfbWFwKSB7CiAgICBhdHRyaWJ1dGVzIDwtIG5hbWVzKGN1ZV9tYXApCgogICAgcmVxdWlyZWRfY29sdW1ucyA8LSBjKAogICAgICAiSUQiLAogICAgICAicGFydHlfbiIsCiAgICAgICJzZWxlY3RlZCIsCiAgICAgIGF0dHJpYnV0ZXMKICAgICkKCiAgICBtaXNzaW5nX2NvbHVtbnMgPC0gc2V0ZGlmZigKICAgICAgcmVxdWlyZWRfY29sdW1ucywKICAgICAgbmFtZXMoZGF0YSkKICAgICkKCiAgICBpZiAobGVuZ3RoKG1pc3NpbmdfY29sdW1ucykgPiAwKSB7CiAgICAgIHN0b3AoIkNoZWNrIHJlbGF0aXZlIHdlaWdodCIpCiAgICB9CgogICAgaWYgKCFhbGwodW5uYW1lKGN1ZV9tYXApICVpbiUgYygicGFydHkiLCAiZWNvbm9taWMiKSkpIHsKICAgICAgc3RvcCgiQ2hlY2sgcmVsYXRpdmUgd2VpZ2h0IikKICAgIH0KCiAgICBhbmFseXNpc19kYXRhIDwtIGRhdGEgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBJRCwKICAgICAgICBwYXJ0eV9uLAogICAgICAgIHNlbGVjdGVkLAogICAgICAgIGFsbF9vZihhdHRyaWJ1dGVzKQogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoSUQpLAogICAgICAgIHBhcnR5X24gPSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihwYXJ0eV9uKSksCiAgICAgICAgc2VsZWN0ZWQgPSBhcy5pbnRlZ2VyKHNlbGVjdGVkKSwKICAgICAgICBhY3Jvc3MoCiAgICAgICAgICBhbGxfb2YoYXR0cmlidXRlcyksCiAgICAgICAgICBhcy5jaGFyYWN0ZXIKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICAhaXMubmEoSUQpLAogICAgICAgIHBhcnR5X24gJWluJSAyOjUsCiAgICAgICAgc2VsZWN0ZWQgJWluJSBjKDBMLCAxTCkKICAgICAgKQoKICAgIG9ic2VydmVkX2NvbmRpdGlvbnMgPC0gc29ydCgKICAgICAgdW5pcXVlKGFuYWx5c2lzX2RhdGEkcGFydHlfbikKICAgICkKCiAgICBpZiAoIWlkZW50aWNhbChvYnNlcnZlZF9jb25kaXRpb25zLCAyOjUpKSB7CiAgICAgIHN0b3AoIkNoZWNrIikKICAgIH0KCiAgICBsb25nX2RhdGEgPC0gYW5hbHlzaXNfZGF0YSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2YoYXR0cmlidXRlcyksCiAgICAgICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwKICAgICAgICB2YWx1ZXNfdG8gPSAibGV2ZWwiCiAgICAgICkgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICAhaXMubmEobGV2ZWwpLAogICAgICAgIGxldmVsICE9ICIiCiAgICAgICkKCiAgICBleHBlY3RlZF9jZWxscyA8LSBsb25nX2RhdGEgJT4lCiAgICAgIGRpc3RpbmN0KAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbAogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgYXR0cmlidXRlX29yZGVyID0gbWF0Y2goCiAgICAgICAgICBhdHRyaWJ1dGUsCiAgICAgICAgICBhdHRyaWJ1dGVzCiAgICAgICAgKQogICAgICApICU+JQogICAgICBhcnJhbmdlKAogICAgICAgIGF0dHJpYnV0ZV9vcmRlciwKICAgICAgICBhdHRyaWJ1dGUsCiAgICAgICAgbGV2ZWwKICAgICAgKSAlPiUKICAgICAgc2VsZWN0KC1hdHRyaWJ1dGVfb3JkZXIpICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgY2VsbF9rZXkgPSBwYXN0ZSgKICAgICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICAgIGxldmVsLAogICAgICAgICAgc2VwID0gIlxyIgogICAgICAgICkKICAgICAgKQoKICAgIHJlc3BvbmRlbnRfY2VsbCA8LSBsb25nX2RhdGEgJT4lCiAgICAgIGdyb3VwX2J5KAogICAgICAgIHBhcnR5X24sCiAgICAgICAgSUQsCiAgICAgICAgYXR0cmlidXRlLAogICAgICAgIGxldmVsCiAgICAgICkgJT4lCiAgICAgIHN1bW1hcmlzZSgKICAgICAgICB5X3N1bSA9IHN1bShzZWxlY3RlZCksCiAgICAgICAgbl9vYnMgPSBuKCksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgY2VsbF9rZXkgPSBwYXN0ZSgKICAgICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICAgIGxldmVsLAogICAgICAgICAgc2VwID0gIlxyIgogICAgICAgICkKICAgICAgKQoKICAgIGNvbmRpdGlvbl9vYmplY3RzIDwtIGxhcHBseSgKICAgICAgMjo1LAogICAgICBmdW5jdGlvbihuX3ZhbHVlKSB7CiAgICAgICAgY29uZGl0aW9uX2RhdGEgPC0gcmVzcG9uZGVudF9jZWxsICU+JQogICAgICAgICAgZmlsdGVyKAogICAgICAgICAgICBwYXJ0eV9uID09IG5fdmFsdWUKICAgICAgICAgICkKCiAgICAgICAgaWRfdmFsdWVzIDwtIHNvcnQoCiAgICAgICAgICB1bmlxdWUoY29uZGl0aW9uX2RhdGEkSUQpCiAgICAgICAgKQogICAgICAgIG5faWRzIDwtIGxlbmd0aChpZF92YWx1ZXMpCiAgICAgICAgbl9jZWxscyA8LSBucm93KGV4cGVjdGVkX2NlbGxzKQoKICAgICAgICBpZiAobl9pZHMgPT0gMCkgewogICAgICAgICAgc3RvcCgiQ2hlY2siKQogICAgICAgIH0KCiAgICAgICAgeV9tYXRyaXggPC0gbWF0cml4KAogICAgICAgICAgMCwKICAgICAgICAgIG5yb3cgPSBuX2lkcywKICAgICAgICAgIG5jb2wgPSBuX2NlbGxzLAogICAgICAgICAgZGltbmFtZXMgPSBsaXN0KAogICAgICAgICAgICBpZF92YWx1ZXMsCiAgICAgICAgICAgIGV4cGVjdGVkX2NlbGxzJGNlbGxfa2V5CiAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBuX21hdHJpeCA8LSBtYXRyaXgoCiAgICAgICAgICAwLAogICAgICAgICAgbnJvdyA9IG5faWRzLAogICAgICAgICAgbmNvbCA9IG5fY2VsbHMsCiAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoCiAgICAgICAgICAgIGlkX3ZhbHVlcywKICAgICAgICAgICAgZXhwZWN0ZWRfY2VsbHMkY2VsbF9rZXkKICAgICAgICAgICkKICAgICAgICApCgogICAgICAgIHJvd19pbmRleCA8LSBtYXRjaCgKICAgICAgICAgIGNvbmRpdGlvbl9kYXRhJElELAogICAgICAgICAgaWRfdmFsdWVzCiAgICAgICAgKQogICAgICAgIGNvbHVtbl9pbmRleCA8LSBtYXRjaCgKICAgICAgICAgIGNvbmRpdGlvbl9kYXRhJGNlbGxfa2V5LAogICAgICAgICAgZXhwZWN0ZWRfY2VsbHMkY2VsbF9rZXkKICAgICAgICApCgogICAgICAgIHlfbWF0cml4W2NiaW5kKHJvd19pbmRleCwgY29sdW1uX2luZGV4KV0gPC0KICAgICAgICAgIGNvbmRpdGlvbl9kYXRhJHlfc3VtCiAgICAgICAgbl9tYXRyaXhbY2JpbmQocm93X2luZGV4LCBjb2x1bW5faW5kZXgpXSA8LQogICAgICAgICAgY29uZGl0aW9uX2RhdGEkbl9vYnMKCiAgICAgICAgaWYgKGFueShjb2xTdW1zKG5fbWF0cml4KSA9PSAwKSkgewogICAgICAgICAgbWlzc2luZ19jZWxscyA8LSBleHBlY3RlZF9jZWxscyRjZWxsX2tleVsKICAgICAgICAgICAgY29sU3VtcyhuX21hdHJpeCkgPT0gMAogICAgICAgICAgXQoKICAgICAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgICAgIH0KCiAgICAgICAgbGlzdCgKICAgICAgICAgIHBhcnR5X24gPSBuX3ZhbHVlLAogICAgICAgICAgaWRzID0gaWRfdmFsdWVzLAogICAgICAgICAgY2VsbF9pbmZvID0gZXhwZWN0ZWRfY2VsbHMsCiAgICAgICAgICB5X21hdHJpeCA9IHlfbWF0cml4LAogICAgICAgICAgbl9tYXRyaXggPSBuX21hdHJpeAogICAgICAgICkKICAgICAgfQogICAgKQoKICAgIG5hbWVzKGNvbmRpdGlvbl9vYmplY3RzKSA8LSBhcy5jaGFyYWN0ZXIoMjo1KQoKICAgIGxpc3QoCiAgICAgIGN1ZV9tYXAgPSBjdWVfbWFwLAogICAgICBhdHRyaWJ1dGVzID0gYXR0cmlidXRlcywKICAgICAgY29uZGl0aW9ucyA9IGNvbmRpdGlvbl9vYmplY3RzCiAgICApCiAgfQoKICBlc3RpbWF0ZV9yZWxhdGl2ZV9jdWVfaW5kaWNlcyA8LSBmdW5jdGlvbigKICAgICAgcHJlcGFyZWQsCiAgICAgIGNsdXN0ZXJfd2VpZ2h0cyA9IE5VTEwKICApIHsKICAgIGNvbmRpdGlvbl9yZXN1bHRzIDwtIGxhcHBseSgKICAgICAgbmFtZXMocHJlcGFyZWQkY29uZGl0aW9ucyksCiAgICAgIGZ1bmN0aW9uKGNvbmRpdGlvbl9uYW1lKSB7CiAgICAgICAgb2JqZWN0IDwtIHByZXBhcmVkJGNvbmRpdGlvbnNbW2NvbmRpdGlvbl9uYW1lXV0KCiAgICAgICAgaWYgKGlzLm51bGwoY2x1c3Rlcl93ZWlnaHRzKSkgewogICAgICAgICAgd2VpZ2h0cyA8LSByZXAoCiAgICAgICAgICAgIDEsCiAgICAgICAgICAgIGxlbmd0aChvYmplY3QkaWRzKQogICAgICAgICAgKQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB3ZWlnaHRzIDwtIGNsdXN0ZXJfd2VpZ2h0c1tbY29uZGl0aW9uX25hbWVdXQogICAgICAgIH0KCiAgICAgICAgaWYgKGxlbmd0aCh3ZWlnaHRzKSAhPSBsZW5ndGgob2JqZWN0JGlkcykpIHsKICAgICAgICAgIHN0b3AoIkNoZWNrIikKICAgICAgICB9CgogICAgICAgIG51bWVyYXRvciA8LSBhcy5udW1lcmljKAogICAgICAgICAgY3Jvc3Nwcm9kKAogICAgICAgICAgICB3ZWlnaHRzLAogICAgICAgICAgICBvYmplY3QkeV9tYXRyaXgKICAgICAgICAgICkKICAgICAgICApCgogICAgICAgIGRlbm9taW5hdG9yIDwtIGFzLm51bWVyaWMoCiAgICAgICAgICBjcm9zc3Byb2QoCiAgICAgICAgICAgIHdlaWdodHMsCiAgICAgICAgICAgIG9iamVjdCRuX21hdHJpeAogICAgICAgICAgKQogICAgICAgICkKCiAgICAgICAgaWYgKGFueShkZW5vbWluYXRvciA8PSAwKSkgewogICAgICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICAgICAgfQoKICAgICAgICBtYXJnaW5hbF9tZWFucyA8LSBudW1lcmF0b3IgLyBkZW5vbWluYXRvcgoKICAgICAgICBtbV90YWJsZSA8LSBvYmplY3QkY2VsbF9pbmZvICU+JQogICAgICAgICAgdHJhbnNtdXRlKAogICAgICAgICAgICBwYXJ0eV9uID0gb2JqZWN0JHBhcnR5X24sCiAgICAgICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICAgICAgbGV2ZWwsCiAgICAgICAgICAgIG1hcmdpbmFsX21lYW4gPSBtYXJnaW5hbF9tZWFucwogICAgICAgICAgKQoKICAgICAgICBhdHRyaWJ1dGVfdGFibGUgPC0gbW1fdGFibGUgJT4lCiAgICAgICAgICBncm91cF9ieSgKICAgICAgICAgICAgcGFydHlfbiwKICAgICAgICAgICAgYXR0cmlidXRlCiAgICAgICAgICApICU+JQogICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICAgICAgICBtZWFuX2Fic29sdXRlX3BhaXJ3aXNlX2RpZmZlcmVuY2UoCiAgICAgICAgICAgICAgICBtYXJnaW5hbF9tZWFuCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgbl9sZXZlbHMgPSBuKCksCiAgICAgICAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICAgICAgICkgJT4lCiAgICAgICAgICBtdXRhdGUoCiAgICAgICAgICAgIGN1ZV9mYW1pbHkgPSB1bm5hbWUoCiAgICAgICAgICAgICAgcHJlcGFyZWQkY3VlX21hcFthdHRyaWJ1dGVdCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGJhc2VsaW5lX3NlbGVjdGlvbl9wcm9iYWJpbGl0eSA9IDEgLyBwYXJ0eV9uLAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlIC8KICAgICAgICAgICAgICAgIGJhc2VsaW5lX3NlbGVjdGlvbl9wcm9iYWJpbGl0eQogICAgICAgICAgKQoKICAgICAgICBjdWVfdGFibGVfbG9uZyA8LSBhdHRyaWJ1dGVfdGFibGUgJT4lCiAgICAgICAgICBncm91cF9ieSgKICAgICAgICAgICAgcGFydHlfbiwKICAgICAgICAgICAgY3VlX2ZhbWlseQogICAgICAgICAgKSAlPiUKICAgICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZSA9IG1lYW4oCiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgKSwKICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9IG1lYW4oCiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICAgICAgKQoKICAgICAgICBwYXJ0eV90YWJsZSA8LSBjdWVfdGFibGVfbG9uZyAlPiUKICAgICAgICAgIGZpbHRlcigKICAgICAgICAgICAgY3VlX2ZhbWlseSA9PSAicGFydHkiCiAgICAgICAgICApICU+JQogICAgICAgICAgdHJhbnNtdXRlKAogICAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkCiAgICAgICAgICApCgogICAgICAgIGVjb25vbWljX3RhYmxlIDwtIGN1ZV90YWJsZV9sb25nICU+JQogICAgICAgICAgZmlsdGVyKAogICAgICAgICAgICBjdWVfZmFtaWx5ID09ICJlY29ub21pYyIKICAgICAgICAgICkgJT4lCiAgICAgICAgICB0cmFuc211dGUoCiAgICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQKICAgICAgICAgICkKCiAgICAgICAgY3VlX3RhYmxlIDwtIGZ1bGxfam9pbigKICAgICAgICAgIHBhcnR5X3RhYmxlLAogICAgICAgICAgZWNvbm9taWNfdGFibGUsCiAgICAgICAgICBieSA9ICJwYXJ0eV9uIgogICAgICAgICkgJT4lCiAgICAgICAgICBtdXRhdGUoCiAgICAgICAgICAgIGJhc2VsaW5lX3NlbGVjdGlvbl9wcm9iYWJpbGl0eSA9IDEgLyBwYXJ0eV9uLAoKICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZSA9CiAgICAgICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSArCiAgICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSwKCiAgICAgICAgICAgIHRvdGFsX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgKwogICAgICAgICAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCgogICAgICAgICAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UgPSBpZl9lbHNlKAogICAgICAgICAgICAgIHRvdGFsX2ltcG9ydGFuY2VfcGFpcndpc2UgPiAwLAogICAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgLwogICAgICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgICAgICBOQV9yZWFsXwogICAgICAgICAgICApLAoKICAgICAgICAgICAgcmVsYXRpdmVfZWNvbm9taWNfd2VpZ2h0X3BhaXJ3aXNlID0KICAgICAgICAgICAgICAxIC0gcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlLAoKICAgICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkID0gaWZfZWxzZSgKICAgICAgICAgICAgICB0b3RhbF9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID4gMCwKICAgICAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIC8KICAgICAgICAgICAgICAgIHRvdGFsX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICAgICAgTkFfcmVhbF8KICAgICAgICAgICAgKSwKCiAgICAgICAgICAgIHJlbGF0aXZlX2Vjb25vbWljX3dlaWdodF9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgICAgICAgMSAtIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZV9hZGp1c3RlZCwKCiAgICAgICAgICAgIGFkanVzdG1lbnRfaWRlbnRpdHlfZGlmZmVyZW5jZSA9CiAgICAgICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkIC0KICAgICAgICAgICAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZQogICAgICAgICAgKQoKICAgICAgICBpZiAoCiAgICAgICAgICBhbnkoCiAgICAgICAgICAgIGFicyhjdWVfdGFibGUkYWRqdXN0bWVudF9pZGVudGl0eV9kaWZmZXJlbmNlKSA+IDFlLTEwLAogICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICkKICAgICAgICApIHsKICAgICAgICAgIHN0b3AoIkNoZWNrIHJlbGF0aXZlIHdlaWdodCIpCiAgICAgICAgfQoKICAgICAgICBsaXN0KAogICAgICAgICAgbWFyZ2luYWxfbWVhbnMgPSBtbV90YWJsZSwKICAgICAgICAgIGF0dHJpYnV0ZV9pbXBvcnRhbmNlID0gYXR0cmlidXRlX3RhYmxlLAogICAgICAgICAgY3VlX2ltcG9ydGFuY2UgPSBjdWVfdGFibGUKICAgICAgICApCiAgICAgIH0KICAgICkKCiAgICBsaXN0KAogICAgICBtYXJnaW5hbF9tZWFucyA9IGJpbmRfcm93cygKICAgICAgICBsYXBwbHkoCiAgICAgICAgICBjb25kaXRpb25fcmVzdWx0cywKICAgICAgICAgIGZ1bmN0aW9uKHgpIHgkbWFyZ2luYWxfbWVhbnMKICAgICAgICApCiAgICAgICksCiAgICAgIGF0dHJpYnV0ZV9pbXBvcnRhbmNlID0gYmluZF9yb3dzKAogICAgICAgIGxhcHBseSgKICAgICAgICAgIGNvbmRpdGlvbl9yZXN1bHRzLAogICAgICAgICAgZnVuY3Rpb24oeCkgeCRhdHRyaWJ1dGVfaW1wb3J0YW5jZQogICAgICAgICkKICAgICAgKSwKICAgICAgY3VlX2ltcG9ydGFuY2UgPSBiaW5kX3Jvd3MoCiAgICAgICAgbGFwcGx5KAogICAgICAgICAgY29uZGl0aW9uX3Jlc3VsdHMsCiAgICAgICAgICBmdW5jdGlvbih4KSB4JGN1ZV9pbXBvcnRhbmNlCiAgICAgICAgKQogICAgICApICU+JQogICAgICAgIGFycmFuZ2UocGFydHlfbikKICAgICkKICB9CgogIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9zbG9wZXMgPC0gZnVuY3Rpb24oY3VlX2ltcG9ydGFuY2UpIHsKICAgIGN1ZV9pbXBvcnRhbmNlIDwtIGN1ZV9pbXBvcnRhbmNlICU+JQogICAgICBhcnJhbmdlKHBhcnR5X24pCgogICAgaWYgKCFpZGVudGljYWwoY3VlX2ltcG9ydGFuY2UkcGFydHlfbiwgMjo1KSkgewogICAgICBzdG9wKCJDaGVjayByZWxhdGl2ZSB3ZWlnaHQiKQogICAgfQoKICAgIHggPC0gY3VlX2ltcG9ydGFuY2UkcGFydHlfbgoKICAgIGMoCiAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSA9CiAgICAgICAgbGluZWFyX3Nsb3BlKAogICAgICAgICAgY3VlX2ltcG9ydGFuY2UkcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlLAogICAgICAgICAgeAogICAgICAgICksCgogICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgeAogICAgICAgICksCgogICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgeAogICAgICAgICksCgogICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgeAogICAgICAgICksCgogICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgeAogICAgICAgICkKICAgICkKICB9CgogIHJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwIDwtIGZ1bmN0aW9uKAogICAgICBwcmVwYXJlZCwKICAgICAgQiwKICAgICAgc2VlZCwKICAgICAgcHJvZ3Jlc3NfZXZlcnkgPSAxMDAKICApIHsKICAgIHNldC5zZWVkKHNlZWQpCgogICAgY29uZGl0aW9uX3Jlc3VsdHMgPC0gdmVjdG9yKAogICAgICAibGlzdCIsCiAgICAgIEIKICAgICkKCiAgICBzbG9wZV9uYW1lcyA8LSBjKAogICAgICAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIiwKICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UiLAogICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiCiAgICApCgogICAgc2xvcGVfbWF0cml4IDwtIG1hdHJpeCgKICAgICAgTkFfcmVhbF8sCiAgICAgIG5yb3cgPSBCLAogICAgICBuY29sID0gbGVuZ3RoKHNsb3BlX25hbWVzKSwKICAgICAgZGltbmFtZXMgPSBsaXN0KAogICAgICAgIE5VTEwsCiAgICAgICAgc2xvcGVfbmFtZXMKICAgICAgKQogICAgKQoKICAgIGZvciAoYiBpbiBzZXFfbGVuKEIpKSB7CiAgICAgIGNsdXN0ZXJfd2VpZ2h0cyA8LSBsYXBwbHkoCiAgICAgICAgcHJlcGFyZWQkY29uZGl0aW9ucywKICAgICAgICBmdW5jdGlvbihvYmplY3QpIHsKICAgICAgICAgIG5faWRzIDwtIGxlbmd0aChvYmplY3QkaWRzKQoKICAgICAgICAgIHNhbXBsZWRfcG9zaXRpb25zIDwtIHNhbXBsZS5pbnQoCiAgICAgICAgICAgIG4gPSBuX2lkcywKICAgICAgICAgICAgc2l6ZSA9IG5faWRzLAogICAgICAgICAgICByZXBsYWNlID0gVFJVRQogICAgICAgICAgKQoKICAgICAgICAgIHRhYnVsYXRlKAogICAgICAgICAgICBzYW1wbGVkX3Bvc2l0aW9ucywKICAgICAgICAgICAgbmJpbnMgPSBuX2lkcwogICAgICAgICAgKQogICAgICAgIH0KICAgICAgKQoKICAgICAgYm9vdHN0cmFwX2VzdGltYXRlcyA8LSBlc3RpbWF0ZV9yZWxhdGl2ZV9jdWVfaW5kaWNlcygKICAgICAgICBwcmVwYXJlZCA9IHByZXBhcmVkLAogICAgICAgIGNsdXN0ZXJfd2VpZ2h0cyA9IGNsdXN0ZXJfd2VpZ2h0cwogICAgICApCgogICAgICBjb25kaXRpb25fcmVzdWx0c1tbYl1dIDwtCiAgICAgICAgYm9vdHN0cmFwX2VzdGltYXRlcyRjdWVfaW1wb3J0YW5jZSAlPiUKICAgICAgICBzZWxlY3QoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKICAgICAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZQogICAgICAgICkgJT4lCiAgICAgICAgbXV0YXRlKAogICAgICAgICAgYm9vdHN0cmFwX3JlcGxpY2F0aW9uID0gYiwKICAgICAgICAgIC5iZWZvcmUgPSAxCiAgICAgICAgKQoKICAgICAgc2xvcGVfbWF0cml4W2IsIF0gPC0gZXN0aW1hdGVfcmVsYXRpdmVfY3VlX3Nsb3BlcygKICAgICAgICBib290c3RyYXBfZXN0aW1hdGVzJGN1ZV9pbXBvcnRhbmNlCiAgICAgICkKCiAgICAgIGlmICgKICAgICAgICBwcm9ncmVzc19ldmVyeSA+IDAgJiYKICAgICAgICAoYiAlJSBwcm9ncmVzc19ldmVyeSA9PSAwIHx8IGIgPT0gQikKICAgICAgKSB7CiAgICAgICAgbWVzc2FnZSgiQm9vdHN0cmFwOiAiLCBiLCAiLyIsIEIpCiAgICAgIH0KICAgIH0KCiAgICBsaXN0KAogICAgICBjb25kaXRpb25fZXN0aW1hdGVzID0gYmluZF9yb3dzKAogICAgICAgIGNvbmRpdGlvbl9yZXN1bHRzCiAgICAgICksCiAgICAgIHNsb3BlcyA9IGFzX3RpYmJsZSgKICAgICAgICBzbG9wZV9tYXRyaXgKICAgICAgKSAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBib290c3RyYXBfcmVwbGljYXRpb24gPSByb3dfbnVtYmVyKCksCiAgICAgICAgICAuYmVmb3JlID0gMQogICAgICAgICkKICAgICkKICB9CgogIHN1bW1hcmlzZV9jb25kaXRpb25faW50ZXJ2YWxzIDwtIGZ1bmN0aW9uKAogICAgICBvYnNlcnZlZF9jdWVfaW1wb3J0YW5jZSwKICAgICAgYm9vdHN0cmFwX2NvbmRpdGlvbl9yZXN1bHRzCiAgKSB7CiAgICBzdGF0aXN0aWNzIDwtIGMoCiAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlIiwKICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UiLAogICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIsCiAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIKICAgICkKCiAgICBvYnNlcnZlZF9sb25nIDwtIG9ic2VydmVkX2N1ZV9pbXBvcnRhbmNlICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgcGFydHlfbiwKICAgICAgICBhbGxfb2Yoc3RhdGlzdGljcykKICAgICAgKSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2Yoc3RhdGlzdGljcyksCiAgICAgICAgbmFtZXNfdG8gPSAic3RhdGlzdGljIiwKICAgICAgICB2YWx1ZXNfdG8gPSAiZXN0aW1hdGUiCiAgICAgICkKCiAgICBib290c3RyYXBfbG9uZyA8LSBib290c3RyYXBfY29uZGl0aW9uX3Jlc3VsdHMgJT4lCiAgICAgIHBpdm90X2xvbmdlcigKICAgICAgICBjb2xzID0gYWxsX29mKHN0YXRpc3RpY3MpLAogICAgICAgIG5hbWVzX3RvID0gInN0YXRpc3RpYyIsCiAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIgogICAgICApICU+JQogICAgICBncm91cF9ieSgKICAgICAgICBwYXJ0eV9uLAogICAgICAgIHN0YXRpc3RpYwogICAgICApICU+JQogICAgICBzdW1tYXJpc2UoCiAgICAgICAgY29uZl9sb3cgPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgdmFsdWUsCiAgICAgICAgICAwLjAyNQogICAgICAgICksCiAgICAgICAgY29uZl9oaWdoID0gc2FmZV9xdWFudGlsZSgKICAgICAgICAgIHZhbHVlLAogICAgICAgICAgMC45NzUKICAgICAgICApLAogICAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICAgKQoKICAgIG9ic2VydmVkX2xvbmcgJT4lCiAgICAgIGxlZnRfam9pbigKICAgICAgICBib290c3RyYXBfbG9uZywKICAgICAgICBieSA9IGMoCiAgICAgICAgICAicGFydHlfbiIsCiAgICAgICAgICAic3RhdGlzdGljIgogICAgICAgICkKICAgICAgKQogIH0KCiAgc3VtbWFyaXNlX3Nsb3BlX2luZmVyZW5jZSA8LSBmdW5jdGlvbigKICAgICAgb2JzZXJ2ZWRfc2xvcGVzLAogICAgICBib290c3RyYXBfc2xvcGVzCiAgKSB7CiAgICBzdGF0aXN0aWNfbmFtZXMgPC0gbmFtZXMob2JzZXJ2ZWRfc2xvcGVzKQoKICAgIG1hcF9kZnIoCiAgICAgIHN0YXRpc3RpY19uYW1lcywKICAgICAgZnVuY3Rpb24oc3RhdGlzdGljX25hbWUpIHsKICAgICAgICBib290c3RyYXBfdmFsdWVzIDwtIGJvb3RzdHJhcF9zbG9wZXNbW3N0YXRpc3RpY19uYW1lXV0KICAgICAgICBib290c3RyYXBfdmFsdWVzIDwtIGJvb3RzdHJhcF92YWx1ZXNbCiAgICAgICAgICBpcy5maW5pdGUoYm9vdHN0cmFwX3ZhbHVlcykKICAgICAgICBdCgogICAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA8LSBjYXNlX3doZW4oCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSA9PQogICAgICAgICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSIgfiAibmVnYXRpdmUiLAogICAgICAgICAgc3RhdGlzdGljX25hbWUgJWluJSBjKAogICAgICAgICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiLAogICAgICAgICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICAgICAgICkgfiAicG9zaXRpdmUiLAogICAgICAgICAgVFJVRSB+ICJub25lIgogICAgICAgICkKCiAgICAgICAgYW5hbHlzaXNfcm9sZSA8LSBjYXNlX3doZW4oCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSAlaW4lIGMoCiAgICAgICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiCiAgICAgICAgICApIH4gImV4cGxvcmF0b3J5X2Nob2ljZV9zZXRfYWRqdXN0ZWQiLAogICAgICAgICAgc3RhdGlzdGljX25hbWUgPT0gInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIgfgogICAgICAgICAgICAiZGVyaXZlZF9yZWxhdGl2ZV9zaGFyZSIsCiAgICAgICAgICBUUlVFIH4gIm1hbnVzY3JpcHRfcHJpbWFyeV91bmFkanVzdGVkIgogICAgICAgICkKCiAgICAgICAgZXN0aW1hdGUgPC0gdW5uYW1lKAogICAgICAgICAgb2JzZXJ2ZWRfc2xvcGVzW1tzdGF0aXN0aWNfbmFtZV1dCiAgICAgICAgKQoKICAgICAgICB0aWJibGUoCiAgICAgICAgICBzdHVkeSA9ICJTdHVkeSAyIiwKICAgICAgICAgIHN0YXRpc3RpYyA9IHN0YXRpc3RpY19uYW1lLAogICAgICAgICAgZXN0aW1hdGUgPSBlc3RpbWF0ZSwKICAgICAgICAgIGNvbmZfbG93ID0gc2FmZV9xdWFudGlsZSgKICAgICAgICAgICAgYm9vdHN0cmFwX3ZhbHVlcywKICAgICAgICAgICAgMC4wMjUKICAgICAgICAgICksCiAgICAgICAgICBjb25mX2hpZ2ggPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgICBib290c3RyYXBfdmFsdWVzLAogICAgICAgICAgICAwLjk3NQogICAgICAgICAgKSwKICAgICAgICAgIHBfdmFsdWVfdHdvX3NpZGVkID0KICAgICAgICAgICAgYm9vdHN0cmFwX3R3b19zaWRlZF9wKAogICAgICAgICAgICAgIGJvb3RzdHJhcF92YWx1ZXMKICAgICAgICAgICAgKSwKICAgICAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA9IGV4cGVjdGVkX2RpcmVjdGlvbiwKICAgICAgICAgIGFuYWx5c2lzX3JvbGUgPSBhbmFseXNpc19yb2xlLAogICAgICAgICAgZXN0aW1hdGVfaW5fZXhwZWN0ZWRfZGlyZWN0aW9uID0gY2FzZV93aGVuKAogICAgICAgICAgICBleHBlY3RlZF9kaXJlY3Rpb24gPT0gInBvc2l0aXZlIiB+IGVzdGltYXRlID4gMCwKICAgICAgICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uID09ICJuZWdhdGl2ZSIgfiBlc3RpbWF0ZSA8IDAsCiAgICAgICAgICAgIFRSVUUgfiBOQQogICAgICAgICAgKQogICAgICAgICkKICAgICAgfQogICAgKQogIH0KCiAgcmVsYXRpdmVfY3VlX3ByZXBhcmVkIDwtIHByZXBhcmVfcmVsYXRpdmVfY3VlX2FuYWx5c2lzKAogICAgZGF0YSA9IGNvbmpvaW50X2FsbF9tLAogICAgY3VlX21hcCA9IHJlbGF0aXZlX2N1ZV9tYXAKICApCgogIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCA8LSBlc3RpbWF0ZV9yZWxhdGl2ZV9jdWVfaW5kaWNlcygKICAgIHByZXBhcmVkID0gcmVsYXRpdmVfY3VlX3ByZXBhcmVkCiAgKQoKICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWRfc2xvcGVzIDwtIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9zbG9wZXMoCiAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkY3VlX2ltcG9ydGFuY2UKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkbWFyZ2luYWxfbWVhbnMsCiAgICAic3R1ZHkyX3JlbGF0aXZlX2N1ZV9tYXJnaW5hbF9tZWFucy5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJGF0dHJpYnV0ZV9pbXBvcnRhbmNlLAogICAgInN0dWR5Ml9yZWxhdGl2ZV9jdWVfYXR0cmlidXRlX2ltcG9ydGFuY2UuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgICJzdHVkeTJfcmVsYXRpdmVfY3VlX2ltcG9ydGFuY2VfYW5kX3dlaWdodC5jc3YiCiAgKQoKICByZWxhdGl2ZV9jb25kaXRpb25fYm9vdHN0cmFwX2ZpbGUgPC0gZmlsZS5wYXRoKAogICAgb3V0cHV0X2RpciwKICAgIHBhc3RlMCgKICAgICAgInN0dWR5Ml9yZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcF8iLAogICAgICB1bmlmaWVkX2NvbmZpZyRjdWVfaW1wb3J0YW5jZV9tZXRyaWNfdmVyc2lvbiwKICAgICAgIl9CIiwKICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CLAogICAgICAiLmNzdiIKICAgICkKICApCgogIHJlbGF0aXZlX3Nsb3BlX2Jvb3RzdHJhcF9maWxlIDwtIGZpbGUucGF0aCgKICAgIG91dHB1dF9kaXIsCiAgICBwYXN0ZTAoCiAgICAgICJzdHVkeTJfcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcF8iLAogICAgICB1bmlmaWVkX2NvbmZpZyRjdWVfaW1wb3J0YW5jZV9tZXRyaWNfdmVyc2lvbiwKICAgICAgIl9CIiwKICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CLAogICAgICAiLmNzdiIKICAgICkKICApCgogIHVzZV9zYXZlZF9yZWxhdGl2ZV9ib290c3RyYXAgPC0KICAgICFyZXJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwICYmCiAgICBmaWxlLmV4aXN0cyhyZWxhdGl2ZV9jb25kaXRpb25fYm9vdHN0cmFwX2ZpbGUpICYmCiAgICBmaWxlLmV4aXN0cyhyZWxhdGl2ZV9zbG9wZV9ib290c3RyYXBfZmlsZSkKCiAgaWYgKHVzZV9zYXZlZF9yZWxhdGl2ZV9ib290c3RyYXApIHsKICAgIG1lc3NhZ2UoIkJvb3RzdHJhcCBjYWNoZSIpCgogICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9ib290c3RyYXAgPC0gcmVhZHI6OnJlYWRfY3N2KAogICAgICByZWxhdGl2ZV9jb25kaXRpb25fYm9vdHN0cmFwX2ZpbGUsCiAgICAgIHNob3dfY29sX3R5cGVzID0gRkFMU0UKICAgICkKCiAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwIDwtIHJlYWRyOjpyZWFkX2NzdigKICAgICAgcmVsYXRpdmVfc2xvcGVfYm9vdHN0cmFwX2ZpbGUsCiAgICAgIHNob3dfY29sX3R5cGVzID0gRkFMU0UKICAgICkKCiAgICBzYXZlZF9CX2NvbmRpdGlvbiA8LSBuX2Rpc3RpbmN0KAogICAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcCRib290c3RyYXBfcmVwbGljYXRpb24KICAgICkKICAgIHNhdmVkX0Jfc2xvcGUgPC0gbl9kaXN0aW5jdCgKICAgICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcCRib290c3RyYXBfcmVwbGljYXRpb24KICAgICkKCiAgICBpZiAoCiAgICAgIHNhdmVkX0JfY29uZGl0aW9uICE9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQiB8fAogICAgICBzYXZlZF9CX3Nsb3BlICE9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQgogICAgKSB7CiAgICAgIG1lc3NhZ2UoIkJvb3RzdHJhcCBjYWNoZSIpCiAgICAgIHVzZV9zYXZlZF9yZWxhdGl2ZV9ib290c3RyYXAgPC0gRkFMU0UKICAgIH0KICB9CgogIGlmICghdXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCkgewogICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCA8LSBydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCgKICAgICAgcHJlcGFyZWQgPSByZWxhdGl2ZV9jdWVfcHJlcGFyZWQsCiAgICAgIEIgPSByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgIHNlZWQgPSByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3NlZWQsCiAgICAgIHByb2dyZXNzX2V2ZXJ5ID0gcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9wcm9ncmVzc19ldmVyeQogICAgKQoKICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwIDwtCiAgICAgIHJlbGF0aXZlX2N1ZV9ib290c3RyYXAkY29uZGl0aW9uX2VzdGltYXRlcwoKICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9ib290c3RyYXAgPC0KICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCRzbG9wZXMKCiAgICByZWFkcjo6d3JpdGVfY3N2KAogICAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcCwKICAgICAgcmVsYXRpdmVfY29uZGl0aW9uX2Jvb3RzdHJhcF9maWxlCiAgICApCgogICAgcmVhZHI6OndyaXRlX2NzdigKICAgICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcCwKICAgICAgcmVsYXRpdmVfc2xvcGVfYm9vdHN0cmFwX2ZpbGUKICAgICkKICB9CgogIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzIDwtIHN1bW1hcmlzZV9jb25kaXRpb25faW50ZXJ2YWxzKAogICAgb2JzZXJ2ZWRfY3VlX2ltcG9ydGFuY2UgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkY3VlX2ltcG9ydGFuY2UsCiAgICBib290c3RyYXBfY29uZGl0aW9uX3Jlc3VsdHMgPQogICAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcAogICkKCiAgcmVsYXRpdmVfY3VlX3Nsb3BlX2luZmVyZW5jZSA8LSBzdW1tYXJpc2Vfc2xvcGVfaW5mZXJlbmNlKAogICAgb2JzZXJ2ZWRfc2xvcGVzID0KICAgICAgcmVsYXRpdmVfY3VlX29ic2VydmVkX3Nsb3BlcywKICAgIGJvb3RzdHJhcF9zbG9wZXMgPQogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMsCiAgICAic3R1ZHkyX3JlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzLmNzdiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlLAogICAgInN0dWR5Ml9yZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlLmNzdiIKICApCgogIHJlbGF0aXZlX2N1ZV9wcmltYXJ5X3Jlc3VsdCA8LSByZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlICU+JQogICAgZmlsdGVyKAogICAgICBzdGF0aXN0aWMgPT0KICAgICAgICAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIgogICAgKQoKICBjYXQoIlxuU3R1ZHkgMu+8muebuOWvvuavlOmHjeOBrue3muW9ouWCvuWQkVxuIikKICBwcmludChyZWxhdGl2ZV9jdWVfcHJpbWFyeV9yZXN1bHQpCgoKICByZWxhdGl2ZV94X29mZnNldCA8LSAwLjA3NQoKICByZWxhdGl2ZV9wYW5lbF9hX2RhdGEgPC0gcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyAlaW4lIGMoCiAgICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UiLAogICAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIgogICAgICApCiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBjdWVfZmFtaWx5ID0gcmVjb2RlKAogICAgICAgIHN0YXRpc3RpYywKICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlID0gIuaUv+WFmuaJi+OBjOOBi+OCiiIsCiAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSA9ICLntYzmuIjmiYvjgYzjgYvjgooiCiAgICAgICksCiAgICAgIGN1ZV9mYW1pbHkgPSBmYWN0b3IoCiAgICAgICAgY3VlX2ZhbWlseSwKICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgIuaUv+WFmuaJi+OBjOOBi+OCiiIsCiAgICAgICAgICAi57WM5riI5omL44GM44GL44KKIgogICAgICAgICkKICAgICAgKSwKICAgICAgeF9wbG90ID0gY2FzZV93aGVuKAogICAgICAgIGN1ZV9mYW1pbHkgPT0gIuaUv+WFmuaJi+OBjOOBi+OCiiIgfgogICAgICAgICAgcGFydHlfbiArIHJlbGF0aXZlX3hfb2Zmc2V0LAogICAgICAgIGN1ZV9mYW1pbHkgPT0gIue1jOa4iOaJi+OBjOOBi+OCiiIgfgogICAgICAgICAgcGFydHlfbiAtIHJlbGF0aXZlX3hfb2Zmc2V0LAogICAgICAgIFRSVUUgfiBhcy5udW1lcmljKHBhcnR5X24pCiAgICAgICksCiAgICAgIHZhbHVlX2xhYmVsID0gc3ByaW50ZigKICAgICAgICAiJS4zZiIsCiAgICAgICAgZXN0aW1hdGUKICAgICAgKQogICAgKQoKICByZWxhdGl2ZV9wYW5lbF9iX2RhdGEgPC0gcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyA9PQogICAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiCiAgICApICU+JQogICAgbXV0YXRlKAogICAgICB2YWx1ZV9sYWJlbCA9IHNwcmludGYoCiAgICAgICAgIiUuMWYlJSIsCiAgICAgICAgMTAwICogZXN0aW1hdGUKICAgICAgKQogICAgKQoKICByZWxhdGl2ZV9hZGp1c3RlZF9sYWJlbF9tYXAgPC0gcmVsYXRpdmVfcGFuZWxfYV9kYXRhICU+JQogICAgZGlzdGluY3QoCiAgICAgIHN0YXRpc3RpYywKICAgICAgY3VlX2ZhbWlseQogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgc3RhdGlzdGljID0gcGFzdGUwKAogICAgICAgIHN0YXRpc3RpYywKICAgICAgICAiX2FkanVzdGVkIgogICAgICApLAogICAgICBjdWVfZmFtaWx5ID0gYXMuY2hhcmFjdGVyKAogICAgICAgIGN1ZV9mYW1pbHkKICAgICAgKQogICAgKQoKICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZF9kYXRhIDwtIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzICU+JQogICAgZmlsdGVyKAogICAgICBzdGF0aXN0aWMgJWluJSBjKAogICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICAgKQogICAgKSAlPiUKICAgIGxlZnRfam9pbigKICAgICAgcmVsYXRpdmVfYWRqdXN0ZWRfbGFiZWxfbWFwLAogICAgICBieSA9ICJzdGF0aXN0aWMiCiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBjdWVfZmFtaWx5ID0gZmFjdG9yKAogICAgICAgIGN1ZV9mYW1pbHksCiAgICAgICAgbGV2ZWxzID0gbGV2ZWxzKAogICAgICAgICAgcmVsYXRpdmVfcGFuZWxfYV9kYXRhJGN1ZV9mYW1pbHkKICAgICAgICApCiAgICAgICksCiAgICAgIHhfcGxvdCA9IGlmX2Vsc2UoCiAgICAgICAgYXMuaW50ZWdlcihjdWVfZmFtaWx5KSA9PSAxTCwKICAgICAgICBwYXJ0eV9uICsgcmVsYXRpdmVfeF9vZmZzZXQsCiAgICAgICAgcGFydHlfbiAtIHJlbGF0aXZlX3hfb2Zmc2V0CiAgICAgICksCiAgICAgIHZhbHVlX2xhYmVsID0gc3ByaW50ZigKICAgICAgICAiJS4xZiUlIiwKICAgICAgICAxMDAgKiBlc3RpbWF0ZQogICAgICApCiAgICApCgogIHJlbGF0aXZlX2NvbmRpdGlvbl9zdWZmaXggPC0gaWYgKAogICAgIuaUv+WFmuWQjeaJi+OBjOOBi+OCiiIgJWluJQogICAgICBsZXZlbHMocmVsYXRpdmVfcGFuZWxfYV9kYXRhJGN1ZV9mYW1pbHkpCiAgKSB7CiAgICAi6YG45oqe6IKiIgogIH0gZWxzZSB7CiAgICAi5pS/5YWaIgogIH0KCiAgcmVsYXRpdmVfY29uZGl0aW9uX2F4aXNfdGl0bGUgPC0gaWYgKAogICAgcmVsYXRpdmVfY29uZGl0aW9uX3N1ZmZpeCA9PSAi6YG45oqe6IKiIgogICkgewogICAgIuaUv+ayu+e1jOa4iOeKtuazgeOBrumBuOaKnuiCouaVsCIKICB9IGVsc2UgewogICAgIuaUv+WFmumBuOaKnuiCouaVsCIKICB9CgogIHJlbGF0aXZlX2ZpZ3VyZV9mb250X2ZhbWlseSA8LSBpZiAoCiAgICAuUGxhdGZvcm0kT1MudHlwZSA9PSAid2luZG93cyIKICApIHsKICAgICJZdSBHb3RoaWMiCiAgfSBlbHNlIHsKICAgICJzYW5zIgogIH0KCiAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncgPC0gdGhlbWVfYncoCiAgICBiYXNlX3NpemUgPSAxMiwKICAgIGJhc2VfZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5CiAgKSArCiAgICB0aGVtZSgKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZSgKICAgICAgICBsaW5ld2lkdGggPSAwLjMwLAogICAgICAgIGNvbG9yID0gImdyZXk4OCIKICAgICAgKSwKICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KAogICAgICAgIGxpbmV3aWR0aCA9IDAuNjUsCiAgICAgICAgY29sb3IgPSAiYmxhY2siCiAgICAgICksCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBjb2xvciA9ICJibGFjayIKICAgICAgKSwKICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBjb2xvciA9ICJibGFjayIKICAgICAgKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gMTIuNSwKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIGhqdXN0ID0gMAogICAgICApLAogICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSA5LjUsCiAgICAgICAgaGp1c3QgPSAwLAogICAgICAgIG1hcmdpbiA9IG1hcmdpbigKICAgICAgICAgIGIgPSA4CiAgICAgICAgKQogICAgICApLAogICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwKICAgICAgbGVnZW5kLmtleS53aWR0aCA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMS4yNSwKICAgICAgICAiY20iCiAgICAgICksCiAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKAogICAgICAgIDgsCiAgICAgICAgMTAsCiAgICAgICAgOCwKICAgICAgICA4CiAgICAgICkKICAgICkKCiAgcmVsYXRpdmVfcGFuZWxfYSA8LSBnZ3Bsb3QoCiAgICByZWxhdGl2ZV9wYW5lbF9hX2RhdGEsCiAgICBhZXMoCiAgICAgIHggPSB4X3Bsb3QsCiAgICAgIHkgPSBlc3RpbWF0ZSwKICAgICAgZ3JvdXAgPSBjdWVfZmFtaWx5LAogICAgICBsaW5ldHlwZSA9IGN1ZV9mYW1pbHkKICAgICkKICApICsKICAgIGdlb21fbGluZSgKICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fZXJyb3JiYXIoCiAgICAgIGFlcygKICAgICAgICB5bWluID0gY29uZl9sb3csCiAgICAgICAgeW1heCA9IGNvbmZfaGlnaAogICAgICApLAogICAgICB3aWR0aCA9IDAuMDc1LAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9sYWJlbCgKICAgICAgYWVzKAogICAgICAgIGxhYmVsID0gdmFsdWVfbGFiZWwKICAgICAgKSwKICAgICAgc2l6ZSA9IDMuNTUsCiAgICAgIGZhbWlseSA9IHJlbGF0aXZlX2ZpZ3VyZV9mb250X2ZhbWlseSwKICAgICAgbGFiZWwuc2l6ZSA9IDAsCiAgICAgIGxhYmVsLnBhZGRpbmcgPSBncmlkOjp1bml0KAogICAgICAgIDAuMTIsCiAgICAgICAgImxpbmVzIgogICAgICApLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygKICAgICAgICAi5pS/5YWa5omL44GM44GL44KKIiA9ICJzb2xpZCIsCiAgICAgICAgIue1jOa4iOaJi+OBjOOBi+OCiiIgPSAiZGFzaGVkIgogICAgICApCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgYnJlYWtzID0gMjo1LAogICAgICBsYWJlbHMgPSBwYXN0ZTAoCiAgICAgICAgMjo1LAogICAgICAgICLmlL/lhZoiCiAgICAgICksCiAgICAgIGxpbWl0cyA9IGMoCiAgICAgICAgMS43MiwKICAgICAgICA1LjI4CiAgICAgICkKICAgICkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKAogICAgICBsYWJlbHMgPSBsYWJlbF9udW1iZXIoCiAgICAgICAgYWNjdXJhY3kgPSAwLjAwNQogICAgICApLAogICAgICBleHBhbmQgPSBleHBhbnNpb24oCiAgICAgICAgbXVsdCA9IGMoCiAgICAgICAgICAwLjA3LAogICAgICAgICAgMC4xMAogICAgICAgICkKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJB77ya5Lih5omL44GM44GL44KK44Gu57W25a++55qE6YeN6KaB5bqmIiwKICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgeCA9ICLmlL/lhZrpgbjmip7ogqLmlbAiLAogICAgICB5ID0gIuaJi+OBjOOBi+OCiumHjeimgeW6piIsCiAgICAgIGxpbmV0eXBlID0gTlVMTAogICAgKSArCiAgICBndWlkZXMoCiAgICAgIGxpbmV0eXBlID0gZ3VpZGVfbGVnZW5kKAogICAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgICBsaW5ld2lkdGggPSAwLjkwCiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIHJlbGF0aXZlX3RoZW1lX2phcGFuZXNlX2J3CgogIHJlbGF0aXZlX2FkanVzdGVkX2xpbmV0eXBlcyA8LSBzZXROYW1lcygKICAgIGMoCiAgICAgICJzb2xpZCIsCiAgICAgICJkYXNoZWQiCiAgICApLAogICAgbGV2ZWxzKAogICAgICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZF9kYXRhJGN1ZV9mYW1pbHkKICAgICkKICApCgogIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkIDwtIGdncGxvdCgKICAgIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEsCiAgICBhZXMoCiAgICAgIHggPSB4X3Bsb3QsCiAgICAgIHkgPSBlc3RpbWF0ZSwKICAgICAgZ3JvdXAgPSBjdWVfZmFtaWx5LAogICAgICBsaW5ldHlwZSA9IGN1ZV9mYW1pbHkKICAgICkKICApICsKICAgIGdlb21fbGluZSgKICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fZXJyb3JiYXIoCiAgICAgIGFlcygKICAgICAgICB5bWluID0gY29uZl9sb3csCiAgICAgICAgeW1heCA9IGNvbmZfaGlnaAogICAgICApLAogICAgICB3aWR0aCA9IDAuMDc1LAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9sYWJlbCgKICAgICAgYWVzKAogICAgICAgIGxhYmVsID0gdmFsdWVfbGFiZWwKICAgICAgKSwKICAgICAgc2l6ZSA9IDMuNTUsCiAgICAgIGZhbWlseSA9IHJlbGF0aXZlX2ZpZ3VyZV9mb250X2ZhbWlseSwKICAgICAgbGFiZWwuc2l6ZSA9IDAsCiAgICAgIGxhYmVsLnBhZGRpbmcgPSBncmlkOjp1bml0KAogICAgICAgIDAuMTIsCiAgICAgICAgImxpbmVzIgogICAgICApLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgdmFsdWVzID0gcmVsYXRpdmVfYWRqdXN0ZWRfbGluZXR5cGVzCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgYnJlYWtzID0gMjo1LAogICAgICBsYWJlbHMgPSBwYXN0ZTAoCiAgICAgICAgMjo1LAogICAgICAgIHJlbGF0aXZlX2NvbmRpdGlvbl9zdWZmaXgKICAgICAgKSwKICAgICAgbGltaXRzID0gYygKICAgICAgICAxLjcyLAogICAgICAgIDUuMjgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGxhYmVsX3BlcmNlbnQoCiAgICAgICAgYWNjdXJhY3kgPSAxCiAgICAgICksCiAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbigKICAgICAgICBtdWx0ID0gYygKICAgICAgICAgIDAuMDcsCiAgICAgICAgICAwLjEwCiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkHvvJrpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqYiLAogICAgICBzdWJ0aXRsZSA9CiAgICAgICAgIuacquiqv+aVtOmHjeimgeW6piDDtyDlubPlnYfpgbjmip7norrnjofvvIgx77yP6YG45oqe6IKi5pWw77yJIiwKICAgICAgeCA9IHJlbGF0aXZlX2NvbmRpdGlvbl9heGlzX3RpdGxlLAogICAgICB5ID0gIuW5s+Wdh+mBuOaKnueiuueOh+OBq+WvvuOBmeOCi+awtOa6lumWk+W3riIsCiAgICAgIGxpbmV0eXBlID0gTlVMTAogICAgKSArCiAgICBndWlkZXMoCiAgICAgIGxpbmV0eXBlID0gZ3VpZGVfbGVnZW5kKAogICAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgICBsaW5ld2lkdGggPSAwLjkwCiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIHJlbGF0aXZlX3RoZW1lX2phcGFuZXNlX2J3CgogIHJlbGF0aXZlX2JfcmFuZ2UgPC0gcmFuZ2UoCiAgICBjKAogICAgICByZWxhdGl2ZV9wYW5lbF9iX2RhdGEkY29uZl9sb3csCiAgICAgIHJlbGF0aXZlX3BhbmVsX2JfZGF0YSRjb25mX2hpZ2gsCiAgICAgIDAuNQogICAgKSwKICAgIG5hLnJtID0gVFJVRQogICkKCiAgcmVsYXRpdmVfYl9wYWRkaW5nIDwtIG1heCgKICAgIDAuMDI1LAogICAgMC4xMCAqIGRpZmYocmVsYXRpdmVfYl9yYW5nZSkKICApCgogIHJlbGF0aXZlX2JfbG93ZXIgPC0gbWF4KAogICAgMCwKICAgIGZsb29yKAogICAgICAyMCAqCiAgICAgICAgKHJlbGF0aXZlX2JfcmFuZ2VbMV0gLSByZWxhdGl2ZV9iX3BhZGRpbmcpCiAgICApIC8gMjAKICApCgogIHJlbGF0aXZlX2JfdXBwZXIgPC0gbWluKAogICAgMSwKICAgIGNlaWxpbmcoCiAgICAgIDIwICoKICAgICAgICAocmVsYXRpdmVfYl9yYW5nZVsyXSArIHJlbGF0aXZlX2JfcGFkZGluZykKICAgICkgLyAyMAogICkKCiAgaWYgKHJlbGF0aXZlX2JfbG93ZXIgPj0gcmVsYXRpdmVfYl91cHBlcikgewogICAgcmVsYXRpdmVfYl9sb3dlciA8LSBtYXgoCiAgICAgIDAsCiAgICAgIHJlbGF0aXZlX2JfbG93ZXIgLSAwLjA1CiAgICApCiAgICByZWxhdGl2ZV9iX3VwcGVyIDwtIG1pbigKICAgICAgMSwKICAgICAgcmVsYXRpdmVfYl91cHBlciArIDAuMDUKICAgICkKICB9CgogIHJlbGF0aXZlX3BhbmVsX2IgPC0gZ2dwbG90KAogICAgcmVsYXRpdmVfcGFuZWxfYl9kYXRhLAogICAgYWVzKAogICAgICB4ID0gcGFydHlfbiwKICAgICAgeSA9IGVzdGltYXRlCiAgICApCiAgKSArCiAgICBnZW9tX2hsaW5lKAogICAgICB5aW50ZXJjZXB0ID0gMC41LAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICBsaW5ld2lkdGggPSAwLjU1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9saW5lKAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKAogICAgICAgIHltaW4gPSBjb25mX2xvdywKICAgICAgICB5bWF4ID0gY29uZl9oaWdoCiAgICAgICksCiAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xhYmVsKAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSB2YWx1ZV9sYWJlbAogICAgICApLAogICAgICBzaXplID0gMy41NSwKICAgICAgZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICBsYWJlbC5zaXplID0gMCwKICAgICAgbGFiZWwucGFkZGluZyA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMC4xMiwKICAgICAgICAibGluZXMiCiAgICAgICksCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBicmVha3MgPSAyOjUsCiAgICAgIGxhYmVscyA9IHBhc3RlMCgKICAgICAgICAyOjUsCiAgICAgICAgIuaUv+WFmiIKICAgICAgKSwKICAgICAgbGltaXRzID0gYygKICAgICAgICAxLjcyLAogICAgICAgIDUuMjgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgIGJyZWFrcyA9IHNlcSgKICAgICAgICByZWxhdGl2ZV9iX2xvd2VyLAogICAgICAgIHJlbGF0aXZlX2JfdXBwZXIsCiAgICAgICAgYnkgPSAwLjA1CiAgICAgICksCiAgICAgIGxhYmVscyA9IGxhYmVsX3BlcmNlbnQoCiAgICAgICAgYWNjdXJhY3kgPSAxCiAgICAgICksCiAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbigKICAgICAgICBtdWx0ID0gYygKICAgICAgICAgIDAuMDUsCiAgICAgICAgICAwLjA4CiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIGNvb3JkX2NhcnRlc2lhbigKICAgICAgeWxpbSA9IGMoCiAgICAgICAgcmVsYXRpdmVfYl9sb3dlciwKICAgICAgICByZWxhdGl2ZV9iX3VwcGVyCiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiQu+8muebuOWvvueahOOBquaUv+WFmuaJi+OBjOOBi+OCiuOBruavlOmHjSIsCiAgICAgIHN1YnRpdGxlID0KICAgICAgICAi5pS/5YWa5omL44GM44GL44KK6YeN6KaB5bqmIMO377yI5pS/5YWa5omL44GM44GL44KK6YeN6KaB5bqm77yL57WM5riI5omL44GM44GL44KK6YeN6KaB5bqm77yJIiwKICAgICAgeCA9ICLmlL/lhZrpgbjmip7ogqLmlbAiLAogICAgICB5ID0gIuebuOWvvueahOOBquaUv+WFmuaJi+OBjOOBi+OCiuavlOmHjSIKICAgICkgKwogICAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncgKwogICAgdGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICAgKQoKICByZWxhdGl2ZV9wYW5lbF9jIDwtIHJlbGF0aXZlX3BhbmVsX2IgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZTAoCiAgICAgICAgIkLvvJrnm7jlr77nmoTjgaoiLAogICAgICAgIGxldmVscyhyZWxhdGl2ZV9wYW5lbF9hX2RhdGEkY3VlX2ZhbWlseSlbMV0sCiAgICAgICAgIuOBruavlOmHjSIKICAgICAgKQogICAgKQoKICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwIDwtICgKICAgIHJlbGF0aXZlX3BhbmVsX2EgfAogICAgICByZWxhdGl2ZV9wYW5lbF9iCiAgKSArCiAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KAogICAgICB3aWR0aHMgPSBjKAogICAgICAgIDEsCiAgICAgICAgMQogICAgICApCiAgICApCgogIHByaW50KAogICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9qcAogICkKCiAgc2F2ZV9wbG90KAogICAgImZpZ19zdHVkeTJfcmVsYXRpdmVfY3VlX3dlaWdodF9qcF9idy5wbmciLAogICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9qcCwKICAgIHdpZHRoID0gMTEuMiwKICAgIGhlaWdodCA9IDUuNCwKICAgIGRwaSA9IDQwMAogICkKCiAgZ2dzYXZlKAogICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJmaWdfc3R1ZHkyX3JlbGF0aXZlX2N1ZV93ZWlnaHRfanBfYncucGRmIgogICAgKSwKICAgIHBsb3QgPSBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwLAogICAgd2lkdGggPSAxMS4yLAogICAgaGVpZ2h0ID0gNS40LAogICAgZGV2aWNlID0gZ3JEZXZpY2VzOjpjYWlyb19wZGYsCiAgICBiZyA9ICJ3aGl0ZSIKICApCgogIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfYWRqdXN0ZWRfanAgPC0gKAogICAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWQgfAogICAgICByZWxhdGl2ZV9wYW5lbF9jCiAgKSArCiAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KAogICAgICB3aWR0aHMgPSBjKAogICAgICAgIDEsCiAgICAgICAgMQogICAgICApCiAgICApCgogIHByaW50KAogICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcAogICkKCiAgcmVsYXRpdmVfYWRqdXN0ZWRfZmlndXJlX3N0dWIgPC0gcGFzdGUwKAogICAgImZpZ19zdHVkeSIsCiAgICBzdHJpbmdyOjpzdHJfZXh0cmFjdCgKICAgICAgc3R1ZHlfbGFiZWwsCiAgICAgICJbMTIzXSIKICAgICksCiAgICAiX3JlbGF0aXZlX2N1ZV93ZWlnaHRfY2hvaWNlX3NldF9hZGp1c3RlZF9qcF9idyIKICApCgogIHNhdmVfcGxvdCgKICAgIHBhc3RlMCgKICAgICAgcmVsYXRpdmVfYWRqdXN0ZWRfZmlndXJlX3N0dWIsCiAgICAgICIucG5nIgogICAgKSwKICAgIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfYWRqdXN0ZWRfanAsCiAgICB3aWR0aCA9IDExLjIsCiAgICBoZWlnaHQgPSA1LjQsCiAgICBkcGkgPSA0MDAKICApCgogIGdnc2F2ZSgKICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKAogICAgICBvdXRwdXRfZGlyLAogICAgICBwYXN0ZTAoCiAgICAgICAgcmVsYXRpdmVfYWRqdXN0ZWRfZmlndXJlX3N0dWIsCiAgICAgICAgIi5wZGYiCiAgICAgICkKICAgICksCiAgICBwbG90ID0gZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcCwKICAgIHdpZHRoID0gMTEuMiwKICAgIGhlaWdodCA9IDUuNCwKICAgIGRldmljZSA9IGdyRGV2aWNlczo6Y2Fpcm9fcGRmLAogICAgYmcgPSAid2hpdGUiCiAgKQoKICByZWxhdGl2ZV9jdWVfcmVzdWx0cyA8LSBsaXN0KAogICAgcHJlcGFyZWQgPSByZWxhdGl2ZV9jdWVfcHJlcGFyZWQsCiAgICBtYXJnaW5hbF9tZWFucyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRtYXJnaW5hbF9tZWFucywKICAgIGF0dHJpYnV0ZV9pbXBvcnRhbmNlID0KICAgICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJGF0dHJpYnV0ZV9pbXBvcnRhbmNlLAogICAgY3VlX2ltcG9ydGFuY2UgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkY3VlX2ltcG9ydGFuY2UsCiAgICBvYnNlcnZlZF9zbG9wZXMgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWRfc2xvcGVzLAogICAgY29uZGl0aW9uX2Jvb3RzdHJhcCA9CiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwLAogICAgc2xvcGVfYm9vdHN0cmFwID0KICAgICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcCwKICAgIGNvbmRpdGlvbl9pbnRlcnZhbHMgPQogICAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscywKICAgIHNsb3BlX2luZmVyZW5jZSA9CiAgICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UsCiAgICBwcmltYXJ5X3Jlc3VsdCA9CiAgICAgIHJlbGF0aXZlX2N1ZV9wcmltYXJ5X3Jlc3VsdCwKICAgIHBsb3RzID0gbGlzdCgKICAgICAgYWJzb2x1dGVfaW1wb3J0YW5jZSA9IHJlbGF0aXZlX3BhbmVsX2EsCiAgICAgIGNob2ljZV9zZXRfYWRqdXN0ZWRfaW1wb3J0YW5jZSA9CiAgICAgICAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWQsCiAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodCA9IHJlbGF0aXZlX3BhbmVsX2IsCiAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYW5lbF9jID0KICAgICAgICByZWxhdGl2ZV9wYW5lbF9jLAogICAgICBjb21iaW5lZCA9IGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAsCiAgICAgIGNvbWJpbmVkX3dpdGhfY2hvaWNlX3NldF9hZGp1c3RtZW50ID0KICAgICAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwCiAgICApCiAgKQoKICBzYXZlUkRTKAogICAgcmVsYXRpdmVfY3VlX3Jlc3VsdHMsCiAgICBmaWxlID0gZmlsZS5wYXRoKAogICAgICBvdXRwdXRfZGlyLAogICAgICAic3R1ZHkyX3JlbGF0aXZlX2N1ZV9yZXN1bHRzLnJkcyIKICAgICkKICApCgoKICBzYXZlUkRTKAogICAgbGlzdCgKICAgICAgc2V0dGluZ3MgPSBsaXN0KAogICAgICAgIHJlcXVpcmVfaW5pdGlhbF9jb25zZW50ID0gcmVxdWlyZV9pbml0aWFsX2NvbnNlbnQsCiAgICAgICAgcmVxdWlyZV9maW5hbF9jb25zZW50ID0gcmVxdWlyZV9maW5hbF9jb25zZW50LAogICAgICAgIHJlcXVpcmVfYXR0ZW50aW9uX2NoZWNrID0gcmVxdWlyZV9hdHRlbnRpb25fY2hlY2ssCiAgICAgICAgcmVxdWlyZV9tYW5pcHVsYXRpb25fY2hlY2sgPSByZXF1aXJlX21hbmlwdWxhdGlvbl9jaGVjawogICAgICApLAogICAgICBzYW1wbGVfZmxvdyA9IHNhbXBsZV9mbG93LAogICAgICBuX2J5X3BhcnR5ID0gbl9ieV9wYXJ0eSwKICAgICAgdmFsaWRfaWRzID0gdmFsaWRfaWRzLAogICAgICBjb25qb2ludF9hbGwgPSBjb25qb2ludF9hbGwsCiAgICAgIGNvbmpvaW50X2FsbF9tID0gY29uam9pbnRfYWxsX20sCiAgICAgIGNvdmFyX2lkID0gY292YXJfaWQsCiAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX25vY292ID0gbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YsCiAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX2NvdiA9IG1vZGVsc19ieV9wYXJ0eV9uX2NvdiwKICAgICAgbV9pbnRlcmFjdGlvbiA9IG1faW50ZXJhY3Rpb24sCiAgICAgIG1vZGVsc19jbG9naXRfbm9jb3YgPSBtb2RlbHNfY2xvZ2l0X25vY292LAogICAgICByZWxhdGl2ZV9jdWUgPSByZWxhdGl2ZV9jdWVfcmVzdWx0cywKICAgICAgcGxvdHMgPSBsaXN0KAogICAgICAgIGFtY2VfY292ID0gcF9hbWNlX2Nvdl9tYWluLAogICAgICAgIGFtY2Vfbm9jb3YgPSBwX2FtY2Vfbm9jb3ZfYXBwZW5kaXgsCiAgICAgICAgaW50ZXJhY3Rpb24gPSBwX2ludGVyYWN0aW9uLAogICAgICAgIGhlYXRtYXAgPSBwX2hlYXRfYW1jZSwKICAgICAgICBoZWF0bWFwX3JhbmsgPSBwX2hlYXRfYW1jZV9yYW5rLAogICAgICAgIGNsb2dpdF9vZGRzX3JhdGlvID0gcF9jbG9naXRfb3IsCiAgICAgICAgcmVsYXRpdmVfY3VlX3dlaWdodCA9IGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAsCiAgICAgICAgcmVsYXRpdmVfY3VlX3dlaWdodF9jaG9pY2Vfc2V0X2FkanVzdGVkID0KICAgICAgICAgIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfYWRqdXN0ZWRfanAKICAgICAgKQogICAgKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgInN0dWR5Ml9hbmFseXNpc19vYmplY3RzLnJkcyIpCiAgKQoKICBjYXB0dXJlLm91dHB1dCgKICAgIHNlc3Npb25JbmZvKCksCiAgICBmaWxlID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJzZXNzaW9uSW5mby50eHQiKQogICkKCiAgY2F0KCIKRG9uZTogIiwgbm9ybWFsaXplUGF0aChvdXRwdXRfZGlyKSwgIgoiLCBzZXAgPSAiIikKCiAgZW52aXJvbm1lbnQoKQp9KQoKCmBgYAoKIyMgQS40IOWun+mokzPvvJrmnKzmlofjga7lm7M344O75ZuzOOODu+WbszkKCmBgYHtyIGE0LXN0dWR5My1jb2RlLCBldmFsPXBhcmFtcyRydW5fYW5hbHlzaXMsIHJlc3VsdHM9J2hpZGUnLCBmaWcuc2hvdz0naGlkZSd9CiMg5pys5paH44Kz44O844OJCnN0dWR5M19lbnYgPC0gbG9jYWwoewpyZXF1aXJlZF9wYWNrYWdlcyA8LSBjKAogICAgImRwbHlyIiwKICAgICJ0aWR5ciIsCiAgICAic3RyaW5nciIsCiAgICAicHVycnIiLAogICAgInJlYWRyIiwKICAgICJmaXhlc3QiLAogICAgInRpYmJsZSIsCiAgICAiZm9yY2F0cyIsCiAgICAiZ2dwbG90MiIsCiAgICAic2NhbGVzIiwKICAgICJzdXJ2aXZhbCIsCiAgICAicGF0Y2h3b3JrIgogICkKCiAgbWlzc2luZ19wYWNrYWdlcyA8LSByZXF1aXJlZF9wYWNrYWdlc1sKICAgICF2YXBwbHkocmVxdWlyZWRfcGFja2FnZXMsIHJlcXVpcmVOYW1lc3BhY2UsIGxvZ2ljYWwoMSksIHF1aWV0bHkgPSBUUlVFKQogIF0KCiAgaWYgKGxlbmd0aChtaXNzaW5nX3BhY2thZ2VzKSA+IDApIHsKICAgIHN0b3AoIk5vIHBhY2thZ2VzIikKICB9CgogIGxpYnJhcnkoZHBseXIpCiAgbGlicmFyeSh0aWR5cikKICBsaWJyYXJ5KHN0cmluZ3IpCiAgbGlicmFyeShwdXJycikKICBsaWJyYXJ5KHJlYWRyKQogIGxpYnJhcnkoZml4ZXN0KQogIGxpYnJhcnkodGliYmxlKQogIGxpYnJhcnkoZm9yY2F0cykKICBsaWJyYXJ5KGdncGxvdDIpCiAgbGlicmFyeShzY2FsZXMpCiAgbGlicmFyeShzdXJ2aXZhbCkKICBsaWJyYXJ5KHBhdGNod29yaykKCiAgZGF0YV9maWxlIDwtIHVuaWZpZWRfY29uZmlnJHN0dWR5MyRkYXRhX2ZpbGUKICBvdXRwdXRfZGlyIDwtIHVuaWZpZWRfY29uZmlnJHN0dWR5MyRvdXRwdXRfZGlyCgogIGRpci5jcmVhdGUob3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgogIHJlcXVpcmVfaW5pdGlhbF9jb25zZW50IDwtIFRSVUUKICByZXF1aXJlX2ZpbmFsX2NvbnNlbnQgPC0gVFJVRQogIGZpbmFsX2NvbnNlbnRfdmFyIDwtICJROC4xIgoKICByZXF1aXJlX2F0dGVudGlvbl9jaGVjayA8LSBUUlVFCiAgcmVxdWlyZV9tYW5pcHVsYXRpb25fY2hlY2sgPC0gVFJVRQoKICByZXF1aXJlX2FsbF9maXZlX3Rhc2tzIDwtIFRSVUUKCiAgYXR0ZW50aW9uX2NoZWNrX3ZhciA8LSAiUTI1LjFfMTEiCiAgYXR0ZW50aW9uX2NoZWNrX2NvcnJlY3QgPC0gIjMiCgogIHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQiA8LSB1bmlmaWVkX2NvbmZpZyRyZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IKICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3NlZWQgPC0gdW5pZmllZF9jb25maWckcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9zZWVkICsgM0wKICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3Byb2dyZXNzX2V2ZXJ5IDwtIHVuaWZpZWRfY29uZmlnJHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfcHJvZ3Jlc3NfZXZlcnkKCiAgcmVydW5fcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCA8LSB1bmlmaWVkX2NvbmZpZyRyZXJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwCgogIGZpZ3VyZV9mb250X2ZhbWlseSA8LSBpZiAoLlBsYXRmb3JtJE9TLnR5cGUgPT0gIndpbmRvd3MiKSB7CiAgICAiWXUgR290aGljIgogIH0gZWxzZSB7CiAgICAiIgogIH0KCgogIG5vcm1fdGV4dCA8LSBmdW5jdGlvbih4KSB7CiAgICB4ICU+JQogICAgICBhcy5jaGFyYWN0ZXIoKSAlPiUKICAgICAgc3RyX3JlcGxhY2VfYWxsKCJcdTMwMDAiLCAiICIpICU+JQogICAgICBzdHJfc3F1aXNoKCkgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgi772eIiwgIn4iKSAlPiUKICAgICAgc3RyX3JlcGxhY2VfYWxsKCLjgJwiLCAifiIpCiAgfQoKICBhc19udW0gPC0gZnVuY3Rpb24oeCkgewogICAgc3VwcHJlc3NXYXJuaW5ncyhyZWFkcjo6cGFyc2VfbnVtYmVyKG5vcm1fdGV4dCh4KSkpCiAgfQoKICBmaXJzdF9leGlzdGluZyA8LSBmdW5jdGlvbihkYXQsIGNhbmRpZGF0ZXMpIHsKICAgIG91dCA8LSBjYW5kaWRhdGVzW2NhbmRpZGF0ZXMgJWluJSBuYW1lcyhkYXQpXQogICAgaWYgKGxlbmd0aChvdXQpID09IDApIHsKICAgICAgTkFfY2hhcmFjdGVyXwogICAgfSBlbHNlIHsKICAgICAgb3V0WzFdCiAgICB9CiAgfQoKICBnZXRfdmFyIDwtIGZ1bmN0aW9uKGRhdCwgY2FuZGlkYXRlcykgewogICAgdiA8LSBmaXJzdF9leGlzdGluZyhkYXQsIGNhbmRpZGF0ZXMpCgogICAgaWYgKGlzLm5hKHYpKSB7CiAgICAgIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KGRhdCkpCiAgICB9IGVsc2UgewogICAgICBkYXRbW3ZdXQogICAgfQogIH0KCiAgaXNfcmVzcG9uc2VfY29kZSA8LSBmdW5jdGlvbih4LCBjb2RlKSB7CiAgICB4X25vcm0gPC0gbm9ybV90ZXh0KHgpCiAgICBjb2RlX2NociA8LSBhcy5jaGFyYWN0ZXIoY29kZSkKCiAgICB4X25vcm0gPT0gY29kZV9jaHIgfAogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgcGFzdGUwKCJcXCgiLCBjb2RlX2NociwgIlxcKSQiKSkKICB9CgogIHJlbGV2ZWxfaWZfcHJlc2VudCA8LSBmdW5jdGlvbih4LCByZWYpIHsKICAgIHggPC0gZmFjdG9yKHgpCgogICAgaWYgKHJlZiAlaW4lIGxldmVscyh4KSkgewogICAgICByZWxldmVsKHgsIHJlZiA9IHJlZikKICAgIH0gZWxzZSB7CiAgICAgIHgKICAgIH0KICB9CgogIGZhY3Rvcl9taXNzIDwtIGZ1bmN0aW9uKHgsIG1pc3MgPSAi5qyg5pCN44O754Sh5Zue562UIikgewogICAgeCA8LSBub3JtX3RleHQoeCkKICAgIHhbaXMubmEoeCkgfCB4ID09ICIiIHwgeCA9PSAiTkEiXSA8LSBtaXNzCiAgICBmYWN0b3IoeCkKICB9CgogIG1lYW5faW1wdXRlIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0gYXMubnVtZXJpYyh4KQogICAgbWlzcyA8LSBhcy5pbnRlZ2VyKGlzLm5hKHgpKQoKICAgIGlmIChhbGwoaXMubmEoeCkpKSB7CiAgICAgIHZhbHVlIDwtIHgKICAgIH0gZWxzZSB7CiAgICAgIHZhbHVlIDwtIGlmZWxzZSgKICAgICAgICBpcy5uYSh4KSwKICAgICAgICBtZWFuKHgsIG5hLnJtID0gVFJVRSksCiAgICAgICAgeAogICAgICApCiAgICB9CgogICAgbGlzdCgKICAgICAgdmFsdWUgPSB2YWx1ZSwKICAgICAgbWlzcyA9IG1pc3MKICAgICkKICB9CgogIHdyaXRlX2Nzdl9zYWZlbHkgPC0gZnVuY3Rpb24oeCwgZmlsZW5hbWUpIHsKICAgIHJlYWRyOjp3cml0ZV9jc3YoCiAgICAgIHgsCiAgICAgIGZpbGUucGF0aChvdXRwdXRfZGlyLCBmaWxlbmFtZSksCiAgICAgIG5hID0gIiIKICAgICkKICB9CgogIHNhdmVfcGxvdCA8LSBmdW5jdGlvbigKICAgIGZpbGVuYW1lLAogICAgcGxvdCwKICAgIHdpZHRoLAogICAgaGVpZ2h0LAogICAgZHBpID0gMzAwCiAgKSB7CiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsIGZpbGVuYW1lKSwKICAgICAgcGxvdCA9IHBsb3QsCiAgICAgIHdpZHRoID0gd2lkdGgsCiAgICAgIGhlaWdodCA9IGhlaWdodCwKICAgICAgZHBpID0gZHBpCiAgICApCiAgfQoKICBjYW5vbmljYWxpemVfcGFydHlfbmFtZSA8LSBmdW5jdGlvbih4KSB7CiAgICB4X25vcm0gPC0gbm9ybV90ZXh0KHgpCiAgICB4X2NvbXBhY3QgPC0gc3RyX3JlcGxhY2VfYWxsKHhfbm9ybSwgIlxccysiLCAiIikKCiAgICBjYXNlX3doZW4oCiAgICAgIGlzLm5hKHhfY29tcGFjdCkgfCB4X2NvbXBhY3QgPT0gIiIgfiBOQV9jaGFyYWN0ZXJfLAoKICAgICAgeF9jb21wYWN0ICVpbiUgYygKICAgICAgICAi6Ieq55Sx5rCR5Li75YWaIiwKICAgICAgICAi6Ieq5rCR5YWaIiwKICAgICAgICAi6Ieq5rCRIgogICAgICApIH4gIuiHqueUseawkeS4u+WFmiIsCgogICAgICB4X2NvbXBhY3QgJWluJSBjKAogICAgICAgICLnq4vmhrLmsJHkuLvlhZoiLAogICAgICAgICLnq4vmsJEiCiAgICAgICkgfiAi56uL5oay5rCR5Li75YWaIiwKCiAgICAgIHhfY29tcGFjdCAlaW4lIGMoCiAgICAgICAgIuaXpeacrOe2reaWsOOBruS8miIsCiAgICAgICAgIue2reaWsCIKICAgICAgKSB+ICLml6XmnKzntq3mlrDjga7kvJoiLAoKICAgICAgeF9jb21wYWN0ID09ICLlhazmmI7lhZoiIH4gIuWFrOaYjuWFmiIsCgogICAgICB4X2NvbXBhY3QgJWluJSBjKAogICAgICAgICLlm73msJHmsJHkuLvlhZoiLAogICAgICAgICLlm73msJEiCiAgICAgICkgfiAi5Zu95rCR5rCR5Li75YWaIiwKCiAgICAgIHhfY29tcGFjdCAlaW4lIGMoCiAgICAgICAgIuOCjOOBhOOCj+aWsOmBuOe1hCIsCiAgICAgICAgIuOCjOOBhOOCjyIKICAgICAgKSB+ICLjgozjgYTjgo/mlrDpgbjntYQiLAoKICAgICAgeF9jb21wYWN0ID09ICLlj4LmlL/lhZoiIH4gIuWPguaUv+WFmiIsCgogICAgICB4X2NvbXBhY3QgJWluJSBjKAogICAgICAgICLml6XmnKzlhbHnlKPlhZoiLAogICAgICAgICLlhbHnlKPlhZoiCiAgICAgICkgfiAi5pel5pys5YWx55Sj5YWaIiwKCiAgICAgIHhfY29tcGFjdCA9PSAi5Lit6YGT5pS56Z2p6YCj5ZCIIiB+ICLkuK3pgZPmlLnpnanpgKPlkIgiLAoKICAgICAgeF9jb21wYWN0ID09ICLml6XmnKzkv53lrojlhZoiIH4gIuaXpeacrOS/neWuiOWFmiIsCgogICAgICB4X2NvbXBhY3QgJWluJSBjKAogICAgICAgICLnpL7kvJrmsJHkuLvlhZoiLAogICAgICAgICLnpL7msJHlhZoiCiAgICAgICkgfiAi56S+5Lya5rCR5Li75YWaIiwKCiAgICAgIHhfY29tcGFjdCA9PSAi44OB44O844Og44G/44KJ44GEIiB+ICLjg4Hjg7zjg6Djgb/jgonjgYQiLAoKICAgICAgVFJVRSB+IHhfbm9ybQogICAgKQogIH0KCiAgY2Fub25pY2FsaXplX2Vjb25vbWljX2xldmVsIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHhfbm9ybSA8LSBub3JtX3RleHQoeCkgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgi77yLIiwgIisiKSAlPiUKICAgICAgc3RyX3JlcGxhY2VfYWxsKCLiiJJ877yNfOKAlSIsICItIikgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgiJSIsICLvvIUiKQoKICAgIGNhc2Vfd2hlbigKICAgICAgaXMubmEoeF9ub3JtKSB8IHhfbm9ybSA9PSAiIiB+IE5BX2NoYXJhY3Rlcl8sCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIkdEUCIpICYKICAgICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuODl+ODqeOCuXxcXCtcXHMqMSIpIH4KICAgICAgICAiR0RQ5oiQ6ZW3546H44OX44Op44K5Me+8hSIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIkdEUCIpICYKICAgICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuODnuOCpOODiuOCuXwtXFxzKjEiKSB+CiAgICAgICAgIkdEUOaIkOmVt+eOh+ODnuOCpOODiuOCuTHvvIUiLAoKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICJHRFAiKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLCsVxccyowfDBcXHMq77yFfOWkieOCj+OCieOBmnzlpInljJbjgarjgZciKSB+CiAgICAgICAgIkdEUOaIkOmVt+eOh8KxMO+8hSIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuaXpee1jOW5s+WdhyIpICYKICAgICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuODl+ODqeOCuXxcXCtcXHMqMTAwMCIpIH4KICAgICAgICAi5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44OX44Op44K5MTAwMOWGhiIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuaXpee1jOW5s+WdhyIpICYKICAgICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuODnuOCpOODiuOCuXwtXFxzKjEwMDAiKSB+CiAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOODnuOCpOODiuOCuTEwMDDlhoYiLAoKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLml6XntYzlubPlnYciKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLlpInjgo/jgonjgZp85aSJ5YyW44Gq44GXfMKxXFxzKjB8MFxccyrlhoYiKSB+CiAgICAgICAgIuaXpee1jOW5s+Wdh+WJjeaciOWQjOacn+avlOWkieOCj+OCieOBmiIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIkNQSXzniankvqEiKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLjg5fjg6njgrl8XFwrXFxzKjEiKSB+CiAgICAgICAgIkNQSeWJjeacn+avlOODl+ODqeOCuTHjg53jgqTjg7Pjg4giLAoKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICJDUEl854mp5L6hIikgJgogICAgICAgIHN0cl9kZXRlY3QoeF9ub3JtLCAi44Oe44Kk44OK44K5fC1cXHMqMSIpIH4KICAgICAgICAiQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIkNQSXzniankvqEiKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLCsVxccyowfDBcXHMq44Od44Kk44Oz44OIfOWkieOCj+OCieOBmnzlpInljJbjgarjgZciKSB+CiAgICAgICAgIkNQSeWJjeacn+avlMKxMOODneOCpOODs+ODiCIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuWksealreeOh3zpm4fnlKgiKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLjg5fjg6njgrl8XFwrXFxzKjEiKSB+CiAgICAgICAgIuWksealreeOh+WJjeacn+avlOODl+ODqeOCuTHvvIUiLAoKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLlpLHmpa3njod86ZuH55SoIikgJgogICAgICAgIHN0cl9kZXRlY3QoeF9ub3JtLCAi44Oe44Kk44OK44K5fC1cXHMqMSIpIH4KICAgICAgICAi5aSx5qWt546H5YmN5pyf5q+U44Oe44Kk44OK44K5Me+8hSIsCgogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIuWksealreeOh3zpm4fnlKgiKSAmCiAgICAgICAgc3RyX2RldGVjdCh4X25vcm0sICLCsVxccyowfDBcXHMq77yFfOWkieOCj+OCieOBmnzlpInljJbjgarjgZciKSB+CiAgICAgICAgIuWksealreeOh+WJjeacn+avlMKxMO+8hSIsCgogICAgICBUUlVFIH4geF9ub3JtCiAgICApCiAgfQoKICBsZXZlbF90b19hdHRyX3ZhciA8LSBmdW5jdGlvbih4KSB7CiAgICB4X25vcm0gPC0gY2Fub25pY2FsaXplX2Vjb25vbWljX2xldmVsKHgpCgogICAgY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KHhfbm9ybSwgIl5HRFDmiJDplbfnjociKSB+ICJnZHBfZ3Jvd3RoIiwKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICJe5pel57WM5bmz5Z2HIikgfiAibmlra2VpIiwKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICJeQ1BJIikgfiAiY3BpIiwKICAgICAgc3RyX2RldGVjdCh4X25vcm0sICJe5aSx5qWt546HIikgfiAidW5lbXBsb3ltZW50IiwKICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICAgICkKICB9CgogIHRpZHlfZml4ZXN0IDwtIGZ1bmN0aW9uKG1vZGVsKSB7CiAgICBjdCA8LSBhcy5kYXRhLmZyYW1lKGZpeGVzdDo6Y29lZnRhYmxlKG1vZGVsKSkKICAgIGN0JHRlcm0gPC0gcm93bmFtZXMoY3QpCgogICAgZXN0aW1hdGVfY29sIDwtIGludGVyc2VjdCgKICAgICAgYygiRXN0aW1hdGUiLCAiZXN0aW1hdGUiKSwKICAgICAgbmFtZXMoY3QpCiAgICApWzFdCgogICAgc2VfY29sIDwtIGludGVyc2VjdCgKICAgICAgYygiU3RkLiBFcnJvciIsICJTdGQuIGVycm9yIiwgInN0ZC5lcnJvciIpLAogICAgICBuYW1lcyhjdCkKICAgIClbMV0KCiAgICBzdGF0aXN0aWNfY29sIDwtIGludGVyc2VjdCgKICAgICAgYygidCB2YWx1ZSIsICJ6IHZhbHVlIiwgInN0YXRpc3RpYyIpLAogICAgICBuYW1lcyhjdCkKICAgIClbMV0KCiAgICBwX2NvbCA8LSBpbnRlcnNlY3QoCiAgICAgIGMoIlByKD58dHwpIiwgIlByKD58enwpIiwgInAudmFsdWUiKSwKICAgICAgbmFtZXMoY3QpCiAgICApWzFdCgogICAgaWYgKAogICAgICBpcy5uYShlc3RpbWF0ZV9jb2wpIHwKICAgICAgICBpcy5uYShzZV9jb2wpIHwKICAgICAgICBpcy5uYShzdGF0aXN0aWNfY29sKSB8CiAgICAgICAgaXMubmEocF9jb2wpCiAgICApIHsKICAgICAgc3RvcCgiQ2hlY2sgZGF0YSIpCiAgICB9CgogICAgY3QgJT4lCiAgICAgIGFzX3RpYmJsZSgpICU+JQogICAgICB0cmFuc211dGUoCiAgICAgICAgdGVybSA9IHRlcm0sCiAgICAgICAgZXN0aW1hdGUgPSAuZGF0YVtbZXN0aW1hdGVfY29sXV0sCiAgICAgICAgc3RkLmVycm9yID0gLmRhdGFbW3NlX2NvbF1dLAogICAgICAgIHN0YXRpc3RpYyA9IC5kYXRhW1tzdGF0aXN0aWNfY29sXV0sCiAgICAgICAgcC52YWx1ZSA9IC5kYXRhW1twX2NvbF1dLAogICAgICAgIGNvbmYubG93ID0gZXN0aW1hdGUgLSAxLjk2ICogc3RkLmVycm9yLAogICAgICAgIGNvbmYuaGlnaCA9IGVzdGltYXRlICsgMS45NiAqIHN0ZC5lcnJvcgogICAgICApCiAgfQoKCiAgaWYgKCFmaWxlLmV4aXN0cyhkYXRhX2ZpbGUpKSB7CiAgICBzdG9wKCJDaGVjayBkYXRhIikKICB9CgogIHJhdyA8LSByZWFkcjo6cmVhZF9jc3YoCiAgICBkYXRhX2ZpbGUsCiAgICBjb2xfdHlwZXMgPSBjb2xzKC5kZWZhdWx0ID0gY29sX2NoYXJhY3RlcigpKSwKICAgIHNob3dfY29sX3R5cGVzID0gRkFMU0UsCiAgICBuYW1lX3JlcGFpciA9ICJtaW5pbWFsIgogICkKCgogIGlmIChyZXF1aXJlX2ZpbmFsX2NvbnNlbnQpIHsKICAgIGZpbmFsX2NvbnNlbnRfdmFyIDwtIGRldGVjdF9maW5hbF9jb25zZW50X2NvbHVtbigKICAgICAgcmF3ID0gcmF3LAogICAgICBwcmVmZXJyZWRfY2FuZGlkYXRlcyA9IGMoIlE4LjEiLCAiUTkuMSIsICJRMTAuMSIpLAogICAgICBzdHVkeV9sYWJlbCA9ICJTdHVkeSAzIgogICAgKQogIH0KCiAgaWYgKHJlcXVpcmVfYXR0ZW50aW9uX2NoZWNrKSB7CiAgICBhdHRlbnRpb25fY2hlY2tfdmFyIDwtIGRldGVjdF9hdHRlbnRpb25fY2hlY2tfY29sdW1uKAogICAgICByYXcgPSByYXcsCiAgICAgIHByZWZlcnJlZF9jYW5kaWRhdGVzID0gYygiUTI1LjFfMTEiLCAiUTI1LjFfMTAiKSwKICAgICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgMyIKICAgICkKICB9CgogIGlmICghIlJlc3BvbnNlSWQiICVpbiUgbmFtZXMocmF3KSkgewogICAgc3RvcCgiQ2hlY2sgZGF0YSIpCiAgfQoKICBkZl9oZWFkZXJfcmVtb3ZlZCA8LSByYXcgJT4lCiAgICBmaWx0ZXIoCiAgICAgICFpcy5uYShSZXNwb25zZUlkKSwKICAgICAgUmVzcG9uc2VJZCAhPSAiIiwKICAgICAgIXN0cl9kZXRlY3QoCiAgICAgICAgbm9ybV90ZXh0KFJlc3BvbnNlSWQpLAogICAgICAgICJeKFJlc3BvbnNlIElEfOWbnuetlElEKSR8SW1wb3J0SWQiCiAgICAgICkKICAgICkgJT4lCiAgICBtdXRhdGUoSUQgPSBhcy5jaGFyYWN0ZXIoUmVzcG9uc2VJZCkpCgogIGR1cGxpY2F0ZV9pZHMgPC0gZGZfaGVhZGVyX3JlbW92ZWQgJT4lCiAgICBjb3VudChJRCkgJT4lCiAgICBmaWx0ZXIobiA+IDEpCgogIGlmIChucm93KGR1cGxpY2F0ZV9pZHMpID4gMCkgewogICAgcHJpbnQoZHVwbGljYXRlX2lkcykKICAgIHN0b3AoIkNoZWNrIikKICB9CgogIHNhbXBsZV9mbG93IDwtIHRpYmJsZSgKICAgIHN0YWdlID0gIlF1YWx0cmljc+izquWVj+aWh+ihjOODu0ltcG9ydElk6KGM44KS6Zmk5aSW5b6MIiwKICAgIG4gPSBucm93KGRmX2hlYWRlcl9yZW1vdmVkKQogICkKCiAgZGYgPC0gZGZfaGVhZGVyX3JlbW92ZWQKCiAgaWYgKHJlcXVpcmVfaW5pdGlhbF9jb25zZW50KSB7CiAgICBpZiAoISJRMS4xIiAlaW4lIG5hbWVzKGRmKSkgewogICAgICBzdG9wKCJDaGVjayBpbml0aWFsIGNvbnNlbnQiKQogICAgfQoKICAgIGRmIDwtIGRmICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgaXNfcmVzcG9uc2VfY29kZShRMS4xLCAxKSB8CiAgICAgICAgICBzdHJfZGV0ZWN0KAogICAgICAgICAgICBub3JtX3RleHQoUTEuMSksCiAgICAgICAgICAgICLotqPml6jjgavlkIzmhI/jgZfjgaYuKuWNlOWKm+OBmeOCiyIKICAgICAgICAgICkKICAgICAgKQoKICAgIHNhbXBsZV9mbG93IDwtIGJpbmRfcm93cygKICAgICAgc2FtcGxlX2Zsb3csCiAgICAgIHRpYmJsZSgKICAgICAgICBzdGFnZSA9ICLliJ3lm57lkIzmhI8gUTEuMSA9IDEiLAogICAgICAgIG4gPSBucm93KGRmKQogICAgICApCiAgICApCiAgfQoKICBpZiAocmVxdWlyZV9maW5hbF9jb25zZW50KSB7CiAgICBpZiAoaXMubmEoZmluYWxfY29uc2VudF92YXIpIHx8ICFmaW5hbF9jb25zZW50X3ZhciAlaW4lIG5hbWVzKGRmKSkgewogICAgICBzdG9wKCJDaGVjayBmaW5hbCBjb25zZW50IikKICAgIH0KCiAgICBkZiA8LSBkZiAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIGlzX3Jlc3BvbnNlX2NvZGUoLmRhdGFbW2ZpbmFsX2NvbnNlbnRfdmFyXV0sIDEpIHwKICAgICAgICAgIHN0cl9kZXRlY3QoCiAgICAgICAgICAgIG5vcm1fdGV4dCguZGF0YVtbZmluYWxfY29uc2VudF92YXJdXSksCiAgICAgICAgICAgICLlkIzmhI/jgZcuKuWbnuetlOe1kOaenOOCkumAgeS/oeOBmeOCiyIKICAgICAgICAgICkKICAgICAgKQoKICAgIHNhbXBsZV9mbG93IDwtIGJpbmRfcm93cygKICAgICAgc2FtcGxlX2Zsb3csCiAgICAgIHRpYmJsZSgKICAgICAgICBzdGFnZSA9IHBhc3RlMCgi5pyA57WC5ZCM5oSPICIsIGZpbmFsX2NvbnNlbnRfdmFyLCAiID0gMSIpLAogICAgICAgIG4gPSBucm93KGRmKQogICAgICApCiAgICApCiAgfQoKICBpZiAocmVxdWlyZV9hdHRlbnRpb25fY2hlY2spIHsKICAgIGlmICghYXR0ZW50aW9uX2NoZWNrX3ZhciAlaW4lIG5hbWVzKGRmKSkgewogICAgICBzdG9wKCJDaGVjayBhdHRlbnRpb24gaXRlbSIpCiAgICB9CgogICAgYXR0ZW50aW9uX2NoZWNrX2NvcnJlY3QgPC0gZGV0ZWN0X2F0dGVudGlvbl9jb3JyZWN0X2NvZGUoCiAgICAgIGRmW1thdHRlbnRpb25fY2hlY2tfdmFyXV0sCiAgICAgIGRpc3BsYXllZF9hbnN3ZXIgPSAzTCwKICAgICAgcmVjb2RlZF9hbnN3ZXIgPSA2TCwKICAgICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgMyIKICAgICkKCiAgICBkZiA8LSBkZiAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIGlzX3Jlc3BvbnNlX2NvZGUoCiAgICAgICAgICAuZGF0YVtbYXR0ZW50aW9uX2NoZWNrX3Zhcl1dLAogICAgICAgICAgYXR0ZW50aW9uX2NoZWNrX2NvcnJlY3QKICAgICAgICApCiAgICAgICkKCiAgICBzYW1wbGVfZmxvdyA8LSBiaW5kX3Jvd3MoCiAgICAgIHNhbXBsZV9mbG93LAogICAgICB0aWJibGUoCiAgICAgICAgc3RhZ2UgPSBwYXN0ZTAoCiAgICAgICAgICAi5oyH56S66aCF55uu5q2j562U77yIIiwKICAgICAgICAgIGF0dGVudGlvbl9jaGVja192YXIsCiAgICAgICAgICAi44CB5L+d5a2Y44Kz44O844OJPSIsCiAgICAgICAgICBhdHRlbnRpb25fY2hlY2tfY29ycmVjdCwKICAgICAgICAgICLvvIkiCiAgICAgICAgKSwKICAgICAgICBuID0gbnJvdyhkZikKICAgICAgKQogICAgKQogIH0KCiAgcHJpbnQoc2FtcGxlX2Zsb3cpCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHNhbXBsZV9mbG93LAogICAgInNhbXBsZV9mbG93X2JlZm9yZV9jb25qb2ludC5jc3YiCiAgKQoKCiAgY2hvaWNlX21hcCA8LSBkZXRlY3RfY29uam9pbnRfY2hvaWNlX21hcCgKICAgIHJhdyA9IHJhdywKICAgIHBhcnR5X251bWJlcnMgPSAyOjUsCiAgICBzdHVkeV9sYWJlbCA9ICJTdHVkeSAzIgogICkKCiAgbWFuaXB1bGF0aW9uX21hcCA8LSBkZXRlY3RfbWFuaXB1bGF0aW9uX21hcCgKICAgIHJhdyA9IHJhdywKICAgIGNob2ljZV9tYXAgPSBjaG9pY2VfbWFwLAogICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgMyIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoY2hvaWNlX21hcCwgImRldGVjdGVkX2Nob2ljZV9xdWVzdGlvbl9tYXAuY3N2IikKICB3cml0ZV9jc3Zfc2FmZWx5KG1hbmlwdWxhdGlvbl9tYXAsICJkZXRlY3RlZF9tYW5pcHVsYXRpb25fcXVlc3Rpb25fbWFwLmNzdiIpCgoKICByZXF1aXJlZF9hdHRyX3ZhcnMgPC0gYygKICAgICJwYXJ0eV9uYW1lIiwKICAgICJnZHBfZ3Jvd3RoIiwKICAgICJuaWtrZWkiLAogICAgImNwaSIsCiAgICAidW5lbXBsb3ltZW50IgogICkKCiAgZXhwZWN0ZWRfcGFydHlfbGV2ZWxzIDwtIGMoCiAgICAi6Ieq55Sx5rCR5Li75YWaIiwKICAgICLnq4vmhrLmsJHkuLvlhZoiLAogICAgIuaXpeacrOe2reaWsOOBruS8miIsCiAgICAi5YWs5piO5YWaIiwKICAgICLlm73msJHmsJHkuLvlhZoiLAogICAgIuOCjOOBhOOCj+aWsOmBuOe1hCIsCiAgICAi5Y+C5pS/5YWaIiwKICAgICLml6XmnKzlhbHnlKPlhZoiLAogICAgIuS4remBk+aUuemdqemAo+WQiCIKICApCgogIGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzIDwtIGxpc3QoCiAgICBnZHBfZ3Jvd3RoID0gYygKICAgICAgIkdEUOaIkOmVt+eOh8KxMO+8hSIsCiAgICAgICJHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICAgIkdEUOaIkOmVt+eOh+ODnuOCpOODiuOCuTHvvIUiCiAgICApLAoKICAgIG5pa2tlaSA9IGMoCiAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5TlpInjgo/jgonjgZoiLAogICAgICAi5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44OX44Op44K5MTAwMOWGhiIsCiAgICAgICLml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5Tjg57jgqTjg4rjgrkxMDAw5YaGIgogICAgKSwKCiAgICBjcGkgPSBjKAogICAgICAiQ1BJ5YmN5pyf5q+UwrEw44Od44Kk44Oz44OIIiwKICAgICAgIkNQSeWJjeacn+avlOODl+ODqeOCuTHjg53jgqTjg7Pjg4giLAogICAgICAiQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIKICAgICksCgogICAgdW5lbXBsb3ltZW50ID0gYygKICAgICAgIuWksealreeOh+WJjeacn+avlMKxMO+8hSIsCiAgICAgICLlpLHmpa3njofliY3mnJ/mr5Tjg5fjg6njgrkx77yFIiwKICAgICAgIuWksealreeOh+WJjeacn+avlOODnuOCpOODiuOCuTHvvIUiCiAgICApCiAgKQoKCiAgbWFrZV9wcm9maWxlX2xvbmcgPC0gZnVuY3Rpb24oZGF0LCBuX3BhcnR5KSB7CgogICAgbWFwX24gPC0gY2hvaWNlX21hcCAlPiUKICAgICAgZmlsdGVyKHBhcnR5X24gPT0gbl9wYXJ0eSkKCiAgICBxdmFycyA8LSBtYXBfbiRjaG9pY2VfdmFyCgogICAgbWlzc2luZ19xIDwtIHNldGRpZmYocXZhcnMsIG5hbWVzKGRhdCkpCgogICAgaWYgKGxlbmd0aChtaXNzaW5nX3EpID4gMCkgewogICAgICBzdG9wKCJDaGVjayBjaG9pY2UgY29sdW1ucyIpCiAgICB9CgogICAgZGF0X24gPC0gZGF0ICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgaWZfYW55KAogICAgICAgICAgYWxsX29mKHF2YXJzKSwKICAgICAgICAgIH4gIWlzLm5hKC54KSAmIG5vcm1fdGV4dCgueCkgIT0gIiIKICAgICAgICApCiAgICAgICkKCiAgICBpZiAocmVxdWlyZV9tYW5pcHVsYXRpb25fY2hlY2spIHsKICAgICAgbWFuaXB1bGF0aW9uX3JvdyA8LSBtYW5pcHVsYXRpb25fbWFwICU+JQogICAgICAgIGZpbHRlcihwYXJ0eV9uID09IG5fcGFydHkpCgogICAgICBtYW5pcHVsYXRpb25fdmFyIDwtIG1hbmlwdWxhdGlvbl9yb3ckbWFuaXB1bGF0aW9uX3ZhcgogICAgICBjb3JyZWN0X2Fuc3dlciA8LSBtYW5pcHVsYXRpb25fcm93JGNvcnJlY3RfYW5zd2VyCgogICAgICBpZiAoIW1hbmlwdWxhdGlvbl92YXIgJWluJSBuYW1lcyhkYXRfbikpIHsKICAgICAgICBzdG9wKCJDaGVjayBtYW5pcHVsYXRpb24gaXRlbSIpCiAgICAgIH0KCiAgICAgIGRhdF9uIDwtIGRhdF9uICU+JQogICAgICAgIGZpbHRlcigKICAgICAgICAgIGlzX3Jlc3BvbnNlX2NvZGUoCiAgICAgICAgICAgIC5kYXRhW1ttYW5pcHVsYXRpb25fdmFyXV0sCiAgICAgICAgICAgIGNvcnJlY3RfYW5zd2VyCiAgICAgICAgICApCiAgICAgICAgKQogICAgfQoKCiAgICBjaG9pY2VfbG9uZyA8LSBkYXRfbiAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELAogICAgICAgIGFsbF9vZihxdmFycykKICAgICAgKSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2YocXZhcnMpLAogICAgICAgIG5hbWVzX3RvID0gImNob2ljZV92YXIiLAogICAgICAgIHZhbHVlc190byA9ICJjaG9pY2VfcmF3IgogICAgICApICU+JQogICAgICBsZWZ0X2pvaW4oCiAgICAgICAgbWFwX24sCiAgICAgICAgYnkgPSAiY2hvaWNlX3ZhciIKICAgICAgKSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIGNob2ljZSA9IHBhcnNlX2Nob2ljZV9wb3NpdGlvbihjaG9pY2VfcmF3KQogICAgICApICU+JQogICAgICBmaWx0ZXIoIWlzLm5hKGNob2ljZSkpICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgSUQsCiAgICAgICAgcGFydHlfbiwKICAgICAgICB0YXNrLAogICAgICAgIGNob2ljZQogICAgICApCgogICAgaW52YWxpZF9jaG9pY2UgPC0gY2hvaWNlX2xvbmcgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBjaG9pY2UgPCAxIHwKICAgICAgICAgIGNob2ljZSA+IG5fcGFydHkKICAgICAgKQoKICAgIGlmIChucm93KGludmFsaWRfY2hvaWNlKSA+IDApIHsKICAgICAgcHJpbnQoaW52YWxpZF9jaG9pY2UpCiAgICAgIHN0b3AoIkNoZWNrIGNob2ljZSB2YWx1ZXMiKQogICAgfQoKICAgIGR1cGxpY2F0ZV9jaG9pY2UgPC0gY2hvaWNlX2xvbmcgJT4lCiAgICAgIGNvdW50KAogICAgICAgIElELAogICAgICAgIHRhc2sKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKG4gIT0gMSkKCiAgICBpZiAobnJvdyhkdXBsaWNhdGVfY2hvaWNlKSA+IDApIHsKICAgICAgcHJpbnQoZHVwbGljYXRlX2Nob2ljZSkKICAgICAgc3RvcCgiQ2hlY2sgZHVwbGljYXRlIGNob2ljZXMiKQogICAgfQoKCiAgICBwYXJ0eV9yZWdleCA8LSBwYXN0ZTAoCiAgICAgICJeUzNfUCIsCiAgICAgIG5fcGFydHksCiAgICAgICJfUEFSVFlfKFsxLTVdKV8oWzEtIiwKICAgICAgbl9wYXJ0eSwKICAgICAgIl0pJCIKICAgICkKCiAgICBwYXJ0eV9jb2xzIDwtIG5hbWVzKGRhdF9uKVsKICAgICAgc3RyX2RldGVjdCgKICAgICAgICBuYW1lcyhkYXRfbiksCiAgICAgICAgcGFydHlfcmVnZXgKICAgICAgKQogICAgXQoKICAgIGV4cGVjdGVkX3BhcnR5X2NvbHNfbiA8LSA1ICogbl9wYXJ0eQoKICAgIGlmIChsZW5ndGgocGFydHlfY29scykgIT0gZXhwZWN0ZWRfcGFydHlfY29sc19uKSB7CiAgICAgIHN0b3AoIkNoZWNrIikKICAgIH0KCiAgICBwYXJ0eV9sb25nIDwtIGRhdF9uICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgSUQsCiAgICAgICAgYWxsX29mKHBhcnR5X2NvbHMpCiAgICAgICkgJT4lCiAgICAgIHBpdm90X2xvbmdlcigKICAgICAgICBjb2xzID0gYWxsX29mKHBhcnR5X2NvbHMpLAogICAgICAgIG5hbWVzX3RvID0gInBhcnR5X3ZhciIsCiAgICAgICAgdmFsdWVzX3RvID0gInBhcnR5X25hbWVfcmF3IgogICAgICApICU+JQogICAgICBleHRyYWN0KAogICAgICAgIHBhcnR5X3ZhciwKICAgICAgICBpbnRvID0gYygKICAgICAgICAgICJ0YXNrIiwKICAgICAgICAgICJwcm9maWxlIgogICAgICAgICksCiAgICAgICAgcmVnZXggPSBwYXJ0eV9yZWdleCwKICAgICAgICBjb252ZXJ0ID0gVFJVRQogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgcGFydHlfbmFtZSA9IGNhbm9uaWNhbGl6ZV9wYXJ0eV9uYW1lKAogICAgICAgICAgcGFydHlfbmFtZV9yYXcKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICB0YXNrICVpbiUgMTo1LAogICAgICAgIHByb2ZpbGUgJWluJSAxOm5fcGFydHksCiAgICAgICAgIWlzLm5hKHBhcnR5X25hbWUpLAogICAgICAgIHBhcnR5X25hbWUgIT0gIiIKICAgICAgKSAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELAogICAgICAgIHRhc2ssCiAgICAgICAgcHJvZmlsZSwKICAgICAgICBwYXJ0eV9uYW1lCiAgICAgICkKCiAgICBkdXBsaWNhdGVfcGFydHlfbmFtZSA8LSBwYXJ0eV9sb25nICU+JQogICAgICBjb3VudCgKICAgICAgICBJRCwKICAgICAgICB0YXNrLAogICAgICAgIHByb2ZpbGUKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKG4gIT0gMSkKCiAgICBpZiAobnJvdyhkdXBsaWNhdGVfcGFydHlfbmFtZSkgPiAwKSB7CiAgICAgIHByaW50KAogICAgICAgIGhlYWQoCiAgICAgICAgICBkdXBsaWNhdGVfcGFydHlfbmFtZSwKICAgICAgICAgIDUwCiAgICAgICAgKQogICAgICApCiAgICAgIHN0b3AoIkNoZWNrIikKICAgIH0KCgogICAgbGV2ZWxfcmVnZXggPC0gcGFzdGUwKAogICAgICAiXlMzX1AiLAogICAgICBuX3BhcnR5LAogICAgICAiX0ZfKFsxLTVdKV8oWzEtIiwKICAgICAgbl9wYXJ0eSwKICAgICAgIl0pXyhbMS00XSkkIgogICAgKQoKICAgIGxldmVsX2NvbHMgPC0gbmFtZXMoZGF0X24pWwogICAgICBzdHJfZGV0ZWN0KAogICAgICAgIG5hbWVzKGRhdF9uKSwKICAgICAgICBsZXZlbF9yZWdleAogICAgICApCiAgICBdCgogICAgZXhwZWN0ZWRfbGV2ZWxfY29sc19uIDwtIDUgKiBuX3BhcnR5ICogNAoKICAgIGlmIChsZW5ndGgobGV2ZWxfY29scykgIT0gZXhwZWN0ZWRfbGV2ZWxfY29sc19uKSB7CiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIGxldmVsX2xvbmcgPC0gZGF0X24gJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBJRCwKICAgICAgICBhbGxfb2YobGV2ZWxfY29scykKICAgICAgKSAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2YobGV2ZWxfY29scyksCiAgICAgICAgbmFtZXNfdG8gPSAiZnZhciIsCiAgICAgICAgdmFsdWVzX3RvID0gImxldmVsX3JhdyIKICAgICAgKSAlPiUKICAgICAgZXh0cmFjdCgKICAgICAgICBmdmFyLAogICAgICAgIGludG8gPSBjKAogICAgICAgICAgInRhc2siLAogICAgICAgICAgInByb2ZpbGUiLAogICAgICAgICAgImF0dHJfb3JkZXIiCiAgICAgICAgKSwKICAgICAgICByZWdleCA9IGxldmVsX3JlZ2V4LAogICAgICAgIGNvbnZlcnQgPSBUUlVFCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBsZXZlbCA9IGNhbm9uaWNhbGl6ZV9lY29ub21pY19sZXZlbCgKICAgICAgICAgIGxldmVsX3JhdwogICAgICAgICksCiAgICAgICAgYXR0cl92YXIgPSBsZXZlbF90b19hdHRyX3ZhcigKICAgICAgICAgIGxldmVsCiAgICAgICAgKQogICAgICApICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgdGFzayAlaW4lIDE6NSwKICAgICAgICBwcm9maWxlICVpbiUgMTpuX3BhcnR5LAogICAgICAgIGF0dHJfb3JkZXIgJWluJSAxOjQsCiAgICAgICAgIWlzLm5hKGxldmVsKSwKICAgICAgICBsZXZlbCAhPSAiIgogICAgICApCgogICAgdW5rbm93bl9sZXZlbHMgPC0gbGV2ZWxfbG9uZyAlPiUKICAgICAgZmlsdGVyKAogICAgICAgIGlzLm5hKGF0dHJfdmFyKQogICAgICApICU+JQogICAgICBkaXN0aW5jdCgKICAgICAgICBsZXZlbF9yYXcsCiAgICAgICAgbGV2ZWwKICAgICAgKQoKICAgIGlmIChucm93KHVua25vd25fbGV2ZWxzKSA+IDApIHsKICAgICAgcHJpbnQodW5rbm93bl9sZXZlbHMpCiAgICAgIHN0b3AoIkNoZWNrIGF0dHJpYnV0ZXMiKQogICAgfQoKICAgIHByb2ZpbGVfYXR0cmlidXRlX2NvdW50IDwtIGxldmVsX2xvbmcgJT4lCiAgICAgIGNvdW50KAogICAgICAgIElELAogICAgICAgIHRhc2ssCiAgICAgICAgcHJvZmlsZSwKICAgICAgICBuYW1lID0gIm5fYXR0cmlidXRlX3Jvd3MiCiAgICAgICkgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBuX2F0dHJpYnV0ZV9yb3dzICE9IDQKICAgICAgKQoKICAgIGlmIChucm93KHByb2ZpbGVfYXR0cmlidXRlX2NvdW50KSA+IDApIHsKICAgICAgcHJpbnQoCiAgICAgICAgaGVhZCgKICAgICAgICAgIHByb2ZpbGVfYXR0cmlidXRlX2NvdW50LAogICAgICAgICAgNTAKICAgICAgICApCiAgICAgICkKICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICB9CgogICAgZHVwbGljYXRlX2F0dHJpYnV0ZSA8LSBsZXZlbF9sb25nICU+JQogICAgICBjb3VudCgKICAgICAgICBJRCwKICAgICAgICB0YXNrLAogICAgICAgIHByb2ZpbGUsCiAgICAgICAgYXR0cl92YXIKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKG4gIT0gMSkKCiAgICBpZiAobnJvdyhkdXBsaWNhdGVfYXR0cmlidXRlKSA+IDApIHsKICAgICAgcHJpbnQoCiAgICAgICAgaGVhZCgKICAgICAgICAgIGR1cGxpY2F0ZV9hdHRyaWJ1dGUsCiAgICAgICAgICA1MAogICAgICAgICkKICAgICAgKQogICAgICBzdG9wKCJDaGVjayBhdHRyaWJ1dGVzIikKICAgIH0KCgogICAgZWNvbm9taWNfd2lkZSA8LSBsZXZlbF9sb25nICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgSUQsCiAgICAgICAgdGFzaywKICAgICAgICBwcm9maWxlLAogICAgICAgIGF0dHJfdmFyLAogICAgICAgIGxldmVsCiAgICAgICkgJT4lCiAgICAgIHBpdm90X3dpZGVyKAogICAgICAgIG5hbWVzX2Zyb20gPSBhdHRyX3ZhciwKICAgICAgICB2YWx1ZXNfZnJvbSA9IGxldmVsLAogICAgICAgIHZhbHVlc19mbiA9IGxpc3QoCiAgICAgICAgICBsZXZlbCA9IH4gZmlyc3QoLngpCiAgICAgICAgKQogICAgICApCgogICAgcHJvZmlsZV93aWRlIDwtIHBhcnR5X2xvbmcgJT4lCiAgICAgIGlubmVyX2pvaW4oCiAgICAgICAgZWNvbm9taWNfd2lkZSwKICAgICAgICBieSA9IGMoCiAgICAgICAgICAiSUQiLAogICAgICAgICAgInRhc2siLAogICAgICAgICAgInByb2ZpbGUiCiAgICAgICAgKQogICAgICApICU+JQogICAgICBpbm5lcl9qb2luKAogICAgICAgIGNob2ljZV9sb25nLAogICAgICAgIGJ5ID0gYygKICAgICAgICAgICJJRCIsCiAgICAgICAgICAidGFzayIKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBwYXJ0eV9uID0gbl9wYXJ0eSwKICAgICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoCiAgICAgICAgICBwcm9maWxlID09IGNob2ljZQogICAgICAgICksCiAgICAgICAgdGFza19pZCA9IHBhc3RlKAogICAgICAgICAgSUQsCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgdGFzaywKICAgICAgICAgIHNlcCA9ICJfIgogICAgICAgICksCiAgICAgICAgcHJvZmlsZV9pZCA9IHBhc3RlKAogICAgICAgICAgSUQsCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgdGFzaywKICAgICAgICAgIHByb2ZpbGUsCiAgICAgICAgICBzZXAgPSAiXyIKICAgICAgICApCiAgICAgICkKCiAgICBtaXNzaW5nX2F0dHIgPC0gc2V0ZGlmZigKICAgICAgcmVxdWlyZWRfYXR0cl92YXJzLAogICAgICBuYW1lcyhwcm9maWxlX3dpZGUpCiAgICApCgogICAgaWYgKGxlbmd0aChtaXNzaW5nX2F0dHIpID4gMCkgewogICAgICBzdG9wKCJDaGVjayBhdHRyaWJ1dGVzIikKICAgIH0KCiAgICBwcm9maWxlX3dpZGUgPC0gcHJvZmlsZV93aWRlICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgSUQsCiAgICAgICAgcGFydHlfbiwKICAgICAgICB0YXNrLAogICAgICAgIHByb2ZpbGUsCiAgICAgICAgY2hvaWNlLAogICAgICAgIHNlbGVjdGVkLAogICAgICAgIHRhc2tfaWQsCiAgICAgICAgcHJvZmlsZV9pZCwKICAgICAgICBhbGxfb2YocmVxdWlyZWRfYXR0cl92YXJzKQogICAgICApICU+JQogICAgICBhcnJhbmdlKAogICAgICAgIElELAogICAgICAgIHRhc2ssCiAgICAgICAgcHJvZmlsZQogICAgICApCgogICAgcmV0dXJuKHByb2ZpbGVfd2lkZSkKICB9CgoKICBjb25qb2ludF8yIDwtIG1ha2VfcHJvZmlsZV9sb25nKAogICAgZGYsCiAgICAyCiAgKQoKICBjb25qb2ludF8zIDwtIG1ha2VfcHJvZmlsZV9sb25nKAogICAgZGYsCiAgICAzCiAgKQoKICBjb25qb2ludF80IDwtIG1ha2VfcHJvZmlsZV9sb25nKAogICAgZGYsCiAgICA0CiAgKQoKICBjb25qb2ludF81IDwtIG1ha2VfcHJvZmlsZV9sb25nKAogICAgZGYsCiAgICA1CiAgKQoKICBjb25qb2ludF9hbGxfdW5maWx0ZXJlZCA8LSBiaW5kX3Jvd3MoCiAgICBjb25qb2ludF8yLAogICAgY29uam9pbnRfMywKICAgIGNvbmpvaW50XzQsCiAgICBjb25qb2ludF81CiAgKQoKCiAgaWRfdGFza19jaGVjayA8LSBjb25qb2ludF9hbGxfdW5maWx0ZXJlZCAlPiUKICAgIGdyb3VwX2J5KAogICAgICBJRCwKICAgICAgcGFydHlfbiwKICAgICAgdGFzawogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl9wcm9maWxlcyA9IG4oKSwKICAgICAgc2VsZWN0ZWRfc3VtID0gc3VtKHNlbGVjdGVkKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKSAlPiUKICAgIGdyb3VwX2J5KAogICAgICBJRCwKICAgICAgcGFydHlfbgogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl90YXNrcyA9IG5fZGlzdGluY3QodGFzayksCiAgICAgIGFsbF90YXNrc19vayA9IGFsbCgKICAgICAgICBuX3Byb2ZpbGVzID09IHBhcnR5X24gJgogICAgICAgICAgc2VsZWN0ZWRfc3VtID09IDEKICAgICAgKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKQoKICBpZiAocmVxdWlyZV9hbGxfZml2ZV90YXNrcykgewogICAgdmFsaWRfaWRzIDwtIGlkX3Rhc2tfY2hlY2sgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBuX3Rhc2tzID09IDUsCiAgICAgICAgYWxsX3Rhc2tzX29rCiAgICAgICkKICB9IGVsc2UgewogICAgdmFsaWRfaWRzIDwtIGlkX3Rhc2tfY2hlY2sgJT4lCiAgICAgIGZpbHRlcihhbGxfdGFza3Nfb2spCiAgfQoKICBjb25qb2ludF9hbGwgPC0gY29uam9pbnRfYWxsX3VuZmlsdGVyZWQgJT4lCiAgICBzZW1pX2pvaW4oCiAgICAgIHZhbGlkX2lkcywKICAgICAgYnkgPSBjKAogICAgICAgICJJRCIsCiAgICAgICAgInBhcnR5X24iCiAgICAgICkKICAgICkKCiAgc2FtcGxlX2Zsb3cgPC0gYmluZF9yb3dzKAogICAgc2FtcGxlX2Zsb3csCiAgICB0aWJibGUoCiAgICAgIHN0YWdlID0gaWYgKHJlcXVpcmVfYWxsX2ZpdmVfdGFza3MpIHsKICAgICAgICAiNeiqsumhjOOBmeOBueOBpuOBjOWujOWFqOOBquWbnuetlOiAhSIKICAgICAgfSBlbHNlIHsKICAgICAgICAi5Zue562U5riI44G/6Kqy6aGM44GM44GZ44G544Gm5a6M5YWo44Gq5Zue562U6ICFIgogICAgICB9LAogICAgICBuID0gbl9kaXN0aW5jdChjb25qb2ludF9hbGwkSUQpCiAgICApCiAgKQoKICBuX2J5X3BhcnR5IDwtIHZhbGlkX2lkcyAlPiUKICAgIGNvdW50KAogICAgICBwYXJ0eV9uLAogICAgICBuYW1lID0gIm4iCiAgICApICU+JQogICAgY29tcGxldGUoCiAgICAgIHBhcnR5X24gPSAyOjUsCiAgICAgIGZpbGwgPSBsaXN0KG4gPSAwKQogICAgKSAlPiUKICAgIGFycmFuZ2UocGFydHlfbikKCiAgbl90b3RhbCA8LSB2YWxpZF9pZHMgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG4gPSBuX2Rpc3RpbmN0KElEKQogICAgKSAlPiUKICAgIHB1bGwobikKCiAgZmlndXJlX25fbGFiZWxzIDwtIGJpbmRfcm93cygKICAgIHRpYmJsZSgKICAgICAgcG9zaXRpb24gPSAi5YWo44K144Oz44OX44OrIiwKICAgICAgbGFiZWwgPSBwYXN0ZTAoCiAgICAgICAgIuWFqOOCteODs+ODl+ODqywgbj0iLAogICAgICAgIHNjYWxlczo6Y29tbWEobl90b3RhbCkKICAgICAgKQogICAgKSwKCiAgICBuX2J5X3BhcnR5ICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgcG9zaXRpb24gPSBwYXN0ZTAoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgIumBuOaKnuiCoiIKICAgICAgICApLAogICAgICAgIGxhYmVsID0gcGFzdGUwKAogICAgICAgICAgIm49IiwKICAgICAgICAgIHNjYWxlczo6Y29tbWEobikKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBsYWJlbAogICAgICApCiAgKQoKICBjYXQoIlxu5YiG5p6Q5a++6LGh6ICF5pWwXG4iKQogIHByaW50KG5fYnlfcGFydHkpCiAgY2F0KAogICAgIuWFqOOCteODs+ODl+ODqyBuPSIsCiAgICBuX3RvdGFsLAogICAgIlxuIiwKICAgIHNlcCA9ICIiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgc2FtcGxlX2Zsb3csCiAgICAic2FtcGxlX2Zsb3cuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIGlkX3Rhc2tfY2hlY2ssCiAgICAiaWRfdGFza19jaGVjay5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgdmFsaWRfaWRzLAogICAgInZhbGlkX2lkcy5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgbl9ieV9wYXJ0eSwKICAgICJuX2J5X3BhcnR5LmNzdiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBmaWd1cmVfbl9sYWJlbHMsCiAgICAiZmlndXJlX25fbGFiZWxzLmNzdiIKICApCgoKICBjaGVja19wcm9maWxlIDwtIGNvbmpvaW50X2FsbCAlPiUKICAgIGdyb3VwX2J5KAogICAgICBwYXJ0eV9uLAogICAgICBJRCwKICAgICAgdGFzaywKICAgICAgdGFza19pZAogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl9wcm9maWxlcyA9IG4oKSwKICAgICAgc2VsZWN0ZWRfc3VtID0gc3VtKHNlbGVjdGVkKSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKSAlPiUKICAgIGNvdW50KAogICAgICBwYXJ0eV9uLAogICAgICBuX3Byb2ZpbGVzLAogICAgICBzZWxlY3RlZF9zdW0KICAgICkKCiAgcHJpbnQoY2hlY2tfcHJvZmlsZSkKCiAgc3RvcGlmbm90KAogICAgYWxsKAogICAgICBjaGVja19wcm9maWxlJG5fcHJvZmlsZXMgPT0KICAgICAgICBjaGVja19wcm9maWxlJHBhcnR5X24KICAgICkKICApCgogIHN0b3BpZm5vdCgKICAgIGFsbCgKICAgICAgY2hlY2tfcHJvZmlsZSRzZWxlY3RlZF9zdW0gPT0gMQogICAgKQogICkKCiAgYWxsb3dlZF9lY29ub21pY19kZiA8LSBlbmZyYW1lKAogICAgYWxsb3dlZF9lY29ub21pY19sZXZlbHMsCiAgICBuYW1lID0gIm5hbWUiLAogICAgdmFsdWUgPSAidmFsdWUiCiAgKSAlPiUKICAgIHVubmVzdCh2YWx1ZSkKCiAgdW5leHBlY3RlZF9lY29ub21pY192YWx1ZXMgPC0gY29uam9pbnRfYWxsICU+JQogICAgc2VsZWN0KAogICAgICBhbGxfb2YoCiAgICAgICAgbmFtZXMoYWxsb3dlZF9lY29ub21pY19sZXZlbHMpCiAgICAgICkKICAgICkgJT4lCiAgICBwaXZvdF9sb25nZXIoCiAgICAgIGNvbHMgPSBldmVyeXRoaW5nKCksCiAgICAgIG5hbWVzX3RvID0gIm5hbWUiLAogICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiCiAgICApICU+JQogICAgZmlsdGVyKAogICAgICAhaXMubmEodmFsdWUpLAogICAgICB2YWx1ZSAhPSAiIgogICAgKSAlPiUKICAgIGRpc3RpbmN0KAogICAgICBuYW1lLAogICAgICB2YWx1ZQogICAgKSAlPiUKICAgIGFudGlfam9pbigKICAgICAgYWxsb3dlZF9lY29ub21pY19kZiwKICAgICAgYnkgPSBjKAogICAgICAgICJuYW1lIiwKICAgICAgICAidmFsdWUiCiAgICAgICkKICAgICkKCiAgcHJpbnQodW5leHBlY3RlZF9lY29ub21pY192YWx1ZXMpCgogIHN0b3BpZm5vdCgKICAgIG5yb3codW5leHBlY3RlZF9lY29ub21pY192YWx1ZXMpID09IDAKICApCgogIG9ic2VydmVkX3BhcnR5X2xldmVscyA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBkaXN0aW5jdChwYXJ0eV9uYW1lKSAlPiUKICAgIGFycmFuZ2UocGFydHlfbmFtZSkKCiAgb2JzZXJ2ZWRfZWNvbm9taWNfbGV2ZWxzIDwtIGNvbmpvaW50X2FsbCAlPiUKICAgIHNlbGVjdCgKICAgICAgYWxsX29mKAogICAgICAgIG5hbWVzKGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzKQogICAgICApCiAgICApICU+JQogICAgcGl2b3RfbG9uZ2VyKAogICAgICBjb2xzID0gZXZlcnl0aGluZygpLAogICAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLAogICAgICB2YWx1ZXNfdG8gPSAibGV2ZWwiCiAgICApICU+JQogICAgZGlzdGluY3QoCiAgICAgIGF0dHJpYnV0ZSwKICAgICAgbGV2ZWwKICAgICkgJT4lCiAgICBhcnJhbmdlKAogICAgICBhdHRyaWJ1dGUsCiAgICAgIGxldmVsCiAgICApCgogIHBhcnR5X2xldmVsX2ZyZXF1ZW5jeSA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBjb3VudCgKICAgICAgcGFydHlfbiwKICAgICAgcGFydHlfbmFtZSwKICAgICAgbmFtZSA9ICJuX3Byb2ZpbGVzIgogICAgKSAlPiUKICAgIGdyb3VwX2J5KHBhcnR5X24pICU+JQogICAgbXV0YXRlKAogICAgICBwcm9wb3J0aW9uID0gbl9wcm9maWxlcyAvCiAgICAgICAgc3VtKG5fcHJvZmlsZXMpCiAgICApICU+JQogICAgdW5ncm91cCgpCgogIGVjb25vbWljX2xldmVsX2ZyZXF1ZW5jeSA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBzZWxlY3QoCiAgICAgIHBhcnR5X24sCiAgICAgIGFsbF9vZigKICAgICAgICBuYW1lcyhhbGxvd2VkX2Vjb25vbWljX2xldmVscykKICAgICAgKQogICAgKSAlPiUKICAgIHBpdm90X2xvbmdlcigKICAgICAgY29scyA9IGFsbF9vZigKICAgICAgICBuYW1lcyhhbGxvd2VkX2Vjb25vbWljX2xldmVscykKICAgICAgKSwKICAgICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwKICAgICAgdmFsdWVzX3RvID0gImxldmVsIgogICAgKSAlPiUKICAgIGNvdW50KAogICAgICBwYXJ0eV9uLAogICAgICBhdHRyaWJ1dGUsCiAgICAgIGxldmVsLAogICAgICBuYW1lID0gIm5fcHJvZmlsZXMiCiAgICApICU+JQogICAgZ3JvdXBfYnkoCiAgICAgIHBhcnR5X24sCiAgICAgIGF0dHJpYnV0ZQogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgcHJvcG9ydGlvbiA9IG5fcHJvZmlsZXMgLwogICAgICAgIHN1bShuX3Byb2ZpbGVzKQogICAgKSAlPiUKICAgIHVuZ3JvdXAoKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgY2hlY2tfcHJvZmlsZSwKICAgICJwcm9maWxlX2V4cGFuc2lvbl9jaGVjay5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgb2JzZXJ2ZWRfcGFydHlfbGV2ZWxzLAogICAgIm9ic2VydmVkX3BhcnR5X2xldmVscy5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgb2JzZXJ2ZWRfZWNvbm9taWNfbGV2ZWxzLAogICAgIm9ic2VydmVkX2Vjb25vbWljX2xldmVscy5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgcGFydHlfbGV2ZWxfZnJlcXVlbmN5LAogICAgInBhcnR5X2xldmVsX2ZyZXF1ZW5jeS5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgZWNvbm9taWNfbGV2ZWxfZnJlcXVlbmN5LAogICAgImVjb25vbWljX2xldmVsX2ZyZXF1ZW5jeS5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgY29uam9pbnRfYWxsLAogICAgInN0dWR5M19wcm9maWxlX2xldmVsX2RhdGEuY3N2IgogICkKCgogIGFuYWx5c2lzX2lkcyA8LSB2YWxpZF9pZHMgJT4lCiAgICBzZWxlY3QoCiAgICAgIElELAogICAgICBwYXJ0eV9uCiAgICApCgogIGlmIChhdHRlbnRpb25fY2hlY2tfdmFyICVpbiUgbmFtZXMoZGYpKSB7CiAgICBhdHRlbnRpb25fc3VtbWFyeSA8LSBkZiAlPiUKICAgICAgc2VtaV9qb2luKAogICAgICAgIGFuYWx5c2lzX2lkcywKICAgICAgICBieSA9ICJJRCIKICAgICAgKSAlPiUKICAgICAgdHJhbnNtdXRlKAogICAgICAgIElELAogICAgICAgIGF0dGVudGlvbl9yZXNwb25zZSA9IG5vcm1fdGV4dCgKICAgICAgICAgIC5kYXRhW1thdHRlbnRpb25fY2hlY2tfdmFyXV0KICAgICAgICApLAogICAgICAgIGF0dGVudGlvbl9wYXNzID0gaXNfcmVzcG9uc2VfY29kZSgKICAgICAgICAgIC5kYXRhW1thdHRlbnRpb25fY2hlY2tfdmFyXV0sCiAgICAgICAgICBhdHRlbnRpb25fY2hlY2tfY29ycmVjdAogICAgICAgICkKICAgICAgKSAlPiUKICAgICAgY291bnQoCiAgICAgICAgYXR0ZW50aW9uX3Jlc3BvbnNlLAogICAgICAgIGF0dGVudGlvbl9wYXNzLAogICAgICAgIG5hbWUgPSAibiIKICAgICAgKSAlPiUKICAgICAgYXJyYW5nZSgKICAgICAgICBkZXNjKGF0dGVudGlvbl9wYXNzKSwKICAgICAgICBhdHRlbnRpb25fcmVzcG9uc2UKICAgICAgKQogIH0gZWxzZSB7CiAgICBhdHRlbnRpb25fc3VtbWFyeSA8LSB0aWJibGUoCiAgICAgIGF0dGVudGlvbl9yZXNwb25zZSA9IGNoYXJhY3RlcigpLAogICAgICBhdHRlbnRpb25fcGFzcyA9IGxvZ2ljYWwoKSwKICAgICAgbiA9IGludGVnZXIoKQogICAgKQogIH0KCiAgbWFuaXB1bGF0aW9uX3N1bW1hcnkgPC0gbWFwX2RmcigKICAgIDI6NSwKICAgIGZ1bmN0aW9uKG5fcGFydHkpIHsKICAgICAgbWFuaXB1bGF0aW9uX3JvdyA8LSBtYW5pcHVsYXRpb25fbWFwICU+JQogICAgICAgIGZpbHRlcigKICAgICAgICAgIHBhcnR5X24gPT0gbl9wYXJ0eQogICAgICAgICkKCiAgICAgIHYgPC0gbWFuaXB1bGF0aW9uX3JvdyRtYW5pcHVsYXRpb25fdmFyCiAgICAgIGNvcnJlY3QgPC0gbWFuaXB1bGF0aW9uX3JvdyRjb3JyZWN0X2Fuc3dlcgoKICAgICAgaWYgKCF2ICVpbiUgbmFtZXMoZGYpKSB7CiAgICAgICAgcmV0dXJuKAogICAgICAgICAgdGliYmxlKAogICAgICAgICAgICBwYXJ0eV9uID0gbl9wYXJ0eSwKICAgICAgICAgICAgcmVzcG9uc2UgPSBOQV9jaGFyYWN0ZXJfLAogICAgICAgICAgICBjb3JyZWN0ID0gTkEsCiAgICAgICAgICAgIG4gPSAwTAogICAgICAgICAgKQogICAgICAgICkKICAgICAgfQoKICAgICAgZGYgJT4lCiAgICAgICAgc2VtaV9qb2luKAogICAgICAgICAgYW5hbHlzaXNfaWRzICU+JQogICAgICAgICAgICBmaWx0ZXIoCiAgICAgICAgICAgICAgcGFydHlfbiA9PSBuX3BhcnR5CiAgICAgICAgICAgICksCiAgICAgICAgICBieSA9ICJJRCIKICAgICAgICApICU+JQogICAgICAgIHRyYW5zbXV0ZSgKICAgICAgICAgIHBhcnR5X24gPSBuX3BhcnR5LAogICAgICAgICAgcmVzcG9uc2UgPSBub3JtX3RleHQoCiAgICAgICAgICAgIC5kYXRhW1t2XV0KICAgICAgICAgICksCiAgICAgICAgICBjb3JyZWN0ID0gaXNfcmVzcG9uc2VfY29kZSgKICAgICAgICAgICAgLmRhdGFbW3ZdXSwKICAgICAgICAgICAgY29ycmVjdAogICAgICAgICAgKQogICAgICAgICkgJT4lCiAgICAgICAgY291bnQoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgcmVzcG9uc2UsCiAgICAgICAgICBjb3JyZWN0LAogICAgICAgICAgbmFtZSA9ICJuIgogICAgICAgICkKICAgIH0KICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBhdHRlbnRpb25fc3VtbWFyeSwKICAgICJhdHRlbnRpb25fY2hlY2tfc3VtbWFyeS5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgbWFuaXB1bGF0aW9uX3N1bW1hcnksCiAgICAicGFydHlfbnVtYmVyX2NoZWNrX3N1bW1hcnkuY3N2IgogICkKCgogIG9ic2VydmVkX3BhcnR5X3ZlY3RvciA8LSBjb25qb2ludF9hbGwgJT4lCiAgICBkaXN0aW5jdChwYXJ0eV9uYW1lKSAlPiUKICAgIHB1bGwocGFydHlfbmFtZSkKCiAgcGFydHlfcmVmZXJlbmNlIDwtIGlmICgKICAgICLoh6rnlLHmsJHkuLvlhZoiICVpbiUgb2JzZXJ2ZWRfcGFydHlfdmVjdG9yCiAgKSB7CiAgICAi6Ieq55Sx5rCR5Li75YWaIgogIH0gZWxzZSB7CiAgICBzb3J0KG9ic2VydmVkX3BhcnR5X3ZlY3RvcilbMV0KICB9CgogIGlmIChwYXJ0eV9yZWZlcmVuY2UgIT0gIuiHqueUseawkeS4u+WFmiIpIHsKICAgIHdhcm5pbmcoIkNoZWNrIikKICB9CgogIHBhcnR5X2xldmVsc191c2UgPC0gYygKICAgIHBhcnR5X3JlZmVyZW5jZSwKCiAgICBleHBlY3RlZF9wYXJ0eV9sZXZlbHNbCiAgICAgIGV4cGVjdGVkX3BhcnR5X2xldmVscyAlaW4lCiAgICAgICAgb2JzZXJ2ZWRfcGFydHlfdmVjdG9yICYKICAgICAgICBleHBlY3RlZF9wYXJ0eV9sZXZlbHMgIT0KICAgICAgICBwYXJ0eV9yZWZlcmVuY2UKICAgIF0sCgogICAgc29ydCgKICAgICAgc2V0ZGlmZigKICAgICAgICBvYnNlcnZlZF9wYXJ0eV92ZWN0b3IsCiAgICAgICAgZXhwZWN0ZWRfcGFydHlfbGV2ZWxzCiAgICAgICkKICAgICkKICApICU+JQogICAgdW5pcXVlKCkKCiAgY29uam9pbnRfYWxsX20gPC0gY29uam9pbnRfYWxsICU+JQogICAgbXV0YXRlKAogICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoc2VsZWN0ZWQpLAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCgogICAgICBwYXJ0eV9uYW1lID0gZmFjdG9yKAogICAgICAgIHBhcnR5X25hbWUsCiAgICAgICAgbGV2ZWxzID0gcGFydHlfbGV2ZWxzX3VzZQogICAgICApLAoKICAgICAgZ2RwX2dyb3d0aCA9IGZhY3RvcigKICAgICAgICBnZHBfZ3Jvd3RoLAogICAgICAgIGxldmVscyA9IGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzJGdkcF9ncm93dGgKICAgICAgKSwKCiAgICAgIG5pa2tlaSA9IGZhY3RvcigKICAgICAgICBuaWtrZWksCiAgICAgICAgbGV2ZWxzID0gYWxsb3dlZF9lY29ub21pY19sZXZlbHMkbmlra2VpCiAgICAgICksCgogICAgICBjcGkgPSBmYWN0b3IoCiAgICAgICAgY3BpLAogICAgICAgIGxldmVscyA9IGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzJGNwaQogICAgICApLAoKICAgICAgdW5lbXBsb3ltZW50ID0gZmFjdG9yKAogICAgICAgIHVuZW1wbG95bWVudCwKICAgICAgICBsZXZlbHMgPSBhbGxvd2VkX2Vjb25vbWljX2xldmVscyR1bmVtcGxveW1lbnQKICAgICAgKSwKCiAgICAgIHBhcnR5X25fZiA9IGZhY3RvcigKICAgICAgICBhcy5jaGFyYWN0ZXIocGFydHlfbiksCiAgICAgICAgbGV2ZWxzID0gYygKICAgICAgICAgICIyIiwKICAgICAgICAgICIzIiwKICAgICAgICAgICI0IiwKICAgICAgICAgICI1IgogICAgICAgICkKICAgICAgKSwKCiAgICAgIHBhcnR5X25fYyA9IHBhcnR5X24gLSAyCiAgICApCgogIGF0dHJfdGVybXMgPC0gYygKICAgICJwYXJ0eV9uYW1lIiwKICAgICJnZHBfZ3Jvd3RoIiwKICAgICJuaWtrZWkiLAogICAgImNwaSIsCiAgICAidW5lbXBsb3ltZW50IgogICkKCiAgZWNvbm9taWNfYXR0cl90ZXJtcyA8LSBjKAogICAgImdkcF9ncm93dGgiLAogICAgIm5pa2tlaSIsCiAgICAiY3BpIiwKICAgICJ1bmVtcGxveW1lbnQiCiAgKQoKCiAgZm9ybXVsYV9ub2NvdiA8LSBhcy5mb3JtdWxhKAogICAgcGFzdGUoCiAgICAgICJzZWxlY3RlZCB+IiwKICAgICAgcGFzdGUoCiAgICAgICAgYXR0cl90ZXJtcywKICAgICAgICBjb2xsYXBzZSA9ICIgKyAiCiAgICAgICkKICAgICkKICApCgogIHJ1bl9hbWNlX25vY292IDwtIGZ1bmN0aW9uKGRhdCkgewogICAgZmVvbHMoCiAgICAgIGZvcm11bGFfbm9jb3YsCiAgICAgIGRhdGEgPSBkYXQsCiAgICAgIHZjb3YgPSB+IElECiAgICApCiAgfQoKICBtb2RlbHNfYnlfcGFydHlfbl9ub2NvdiA8LSBjb25qb2ludF9hbGxfbSAlPiUKICAgIHNwbGl0KC4kcGFydHlfbikgJT4lCiAgICBtYXAocnVuX2FtY2Vfbm9jb3YpCgogIGNhcHR1cmUub3V0cHV0KAogICAgZXRhYmxlKAogICAgICBtb2RlbHNfYnlfcGFydHlfbl9ub2NvdgogICAgKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJhbWNlX25vY292X21vZGVscy50eHQiCiAgICApCiAgKQoKCiAgbV9pbnRlcmFjdGlvbiA8LSBmZW9scygKICAgIHNlbGVjdGVkIH4KICAgICAgcGFydHlfbl9mICoKICAgICAgKAogICAgICAgIHBhcnR5X25hbWUgKwogICAgICAgICAgZ2RwX2dyb3d0aCArCiAgICAgICAgICBuaWtrZWkgKwogICAgICAgICAgY3BpICsKICAgICAgICAgIHVuZW1wbG95bWVudAogICAgICApLAogICAgZGF0YSA9IGNvbmpvaW50X2FsbF9tLAogICAgdmNvdiA9IH4gSUQKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc3VtbWFyeShtX2ludGVyYWN0aW9uKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJhbWNlX2ludGVyYWN0aW9uX21vZGVsLnR4dCIKICAgICkKICApCgoKICBtX2xpbmVhcl90cmVuZCA8LSBmZW9scygKICAgIHNlbGVjdGVkIH4KICAgICAgcGFydHlfbl9jICoKICAgICAgKAogICAgICAgIHBhcnR5X25hbWUgKwogICAgICAgICAgZ2RwX2dyb3d0aCArCiAgICAgICAgICBuaWtrZWkgKwogICAgICAgICAgY3BpICsKICAgICAgICAgIHVuZW1wbG95bWVudAogICAgICApLAogICAgZGF0YSA9IGNvbmpvaW50X2FsbF9tLAogICAgdmNvdiA9IH4gSUQKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc3VtbWFyeShtX2xpbmVhcl90cmVuZCksCiAgICBmaWxlID0gZmlsZS5wYXRoKAogICAgICBvdXRwdXRfZGlyLAogICAgICAiYW1jZV9saW5lYXJfdHJlbmRfbW9kZWwudHh0IgogICAgKQogICkKCgogIHBhcnR5X3Rlcm1fbGFiZWxzIDwtIHRpYmJsZSgKICAgIHRlcm0gPSBwYXN0ZTAoCiAgICAgICJwYXJ0eV9uYW1lIiwKICAgICAgcGFydHlfbGV2ZWxzX3VzZVstMV0KICAgICksCiAgICBhdHRyaWJ1dGUgPSAi5pS/5qip5LiO5YWa44Gu5pS/5YWa5ZCNIiwKICAgIGN1ZV90eXBlID0gIuaUv+WFmuWQjeOBruaJi+OBjOOBi+OCiiIsCiAgICBsYWJlbCA9IHBhcnR5X2xldmVsc191c2VbLTFdLAogICAgb3JkZXIgPSBzZXFfYWxvbmcoCiAgICAgIHBhcnR5X2xldmVsc191c2VbLTFdCiAgICApCiAgKQoKICBlY29ub21pY190ZXJtX2xhYmVscyA8LSB0cmliYmxlKAogICAgfnRlcm0sIH5hdHRyaWJ1dGUsIH5jdWVfdHlwZSwgfmxhYmVsLCB+b3JkZXIsCgogICAgImdkcF9ncm93dGhHRFDmiJDplbfnjofjg5fjg6njgrkx77yFIiwKICAgICJHRFDmiJDplbfnjociLAogICAgIue1jOa4iOOBruaJi+OBjOOBi+OCiiIsCiAgICAiR0RQ77ya44OX44Op44K5Me+8hSIsCiAgICAxLAoKICAgICJnZHBfZ3Jvd3RoR0RQ5oiQ6ZW3546H44Oe44Kk44OK44K5Me+8hSIsCiAgICAiR0RQ5oiQ6ZW3546HIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIkdEUO+8muODnuOCpOODiuOCuTHvvIUiLAogICAgMiwKCiAgICAibmlra2Vp5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44OX44Op44K5MTAwMOWGhiIsCiAgICAi5pel57WM5bmz5Z2HIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIuaXpee1jOW5s+Wdh++8muODl+ODqeOCuTEwMDDlhoYiLAogICAgMywKCiAgICAibmlra2Vp5pel57WM5bmz5Z2H5YmN5pyI5ZCM5pyf5q+U44Oe44Kk44OK44K5MTAwMOWGhiIsCiAgICAi5pel57WM5bmz5Z2HIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIuaXpee1jOW5s+Wdh++8muODnuOCpOODiuOCuTEwMDDlhoYiLAogICAgNCwKCiAgICAiY3BpQ1BJ5YmN5pyf5q+U44OX44Op44K5MeODneOCpOODs+ODiCIsCiAgICAiQ1BJIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIkNQSe+8muODl+ODqeOCuTHjg53jgqTjg7Pjg4giLAogICAgNSwKCiAgICAiY3BpQ1BJ5YmN5pyf5q+U44Oe44Kk44OK44K5MeODneOCpOODs+ODiCIsCiAgICAiQ1BJIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIkNQSe+8muODnuOCpOODiuOCuTHjg53jgqTjg7Pjg4giLAogICAgNiwKCiAgICAidW5lbXBsb3ltZW505aSx5qWt546H5YmN5pyf5q+U44OX44Op44K5Me+8hSIsCiAgICAi5aSx5qWt546HIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIuWksealreeOh++8muODl+ODqeOCuTHvvIUiLAogICAgNywKCiAgICAidW5lbXBsb3ltZW505aSx5qWt546H5YmN5pyf5q+U44Oe44Kk44OK44K5Me+8hSIsCiAgICAi5aSx5qWt546HIiwKICAgICLntYzmuIjjga7miYvjgYzjgYvjgooiLAogICAgIuWksealreeOh++8muODnuOCpOODiuOCuTHvvIUiLAogICAgOAogICkKCiAgdGVybV9sYWJlbHMgPC0gYmluZF9yb3dzKAogICAgcGFydHlfdGVybV9sYWJlbHMgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBvcmRlcl9nbG9iYWwgPSBvcmRlcgogICAgICApLAoKICAgIGVjb25vbWljX3Rlcm1fbGFiZWxzICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgb3JkZXJfZ2xvYmFsID0KICAgICAgICAgIG1heCgKICAgICAgICAgICAgYygKICAgICAgICAgICAgICBwYXJ0eV90ZXJtX2xhYmVscyRvcmRlciwKICAgICAgICAgICAgICAwCiAgICAgICAgICAgICkKICAgICAgICAgICkgKwogICAgICAgICAgb3JkZXIKICAgICAgKQogICkgJT4lCiAgICBzZWxlY3QoCiAgICAgIHRlcm0sCiAgICAgIGF0dHJpYnV0ZSwKICAgICAgY3VlX3R5cGUsCiAgICAgIGxhYmVsLAogICAgICBvcmRlciA9IG9yZGVyX2dsb2JhbAogICAgKQoKICBhdHRyaWJ1dGVfb3JkZXIgPC0gYygKICAgICLmlL/mqKnkuI7lhZrjga7mlL/lhZrlkI0iLAogICAgIkdEUOaIkOmVt+eOhyIsCiAgICAi5pel57WM5bmz5Z2HIiwKICAgICJDUEkiLAogICAgIuWksealreeOhyIKICApCgogIGxhYmVsX29yZGVyIDwtIHRlcm1fbGFiZWxzICU+JQogICAgYXJyYW5nZShvcmRlcikgJT4lCiAgICBwdWxsKGxhYmVsKQoKICBtYWtlX2FtY2VfcGxvdF9kZiA8LSBmdW5jdGlvbihtb2RlbHMpIHsKICAgIGltYXBfZGZyKAogICAgICBtb2RlbHMsCiAgICAgIH4gdGlkeV9maXhlc3QoLngpICU+JQogICAgICAgIG11dGF0ZSgKICAgICAgICAgIHBhcnR5X24gPSBhcy5jaGFyYWN0ZXIoLnkpCiAgICAgICAgKQogICAgKSAlPiUKICAgICAgbGVmdF9qb2luKAogICAgICAgIHRlcm1fbGFiZWxzLAogICAgICAgIGJ5ID0gInRlcm0iCiAgICAgICkgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICAhaXMubmEoYXR0cmlidXRlKQogICAgICApICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgICBjb25mLmxvd19wcCA9IGNvbmYubG93ICogMTAwLAogICAgICAgIGNvbmYuaGlnaF9wcCA9IGNvbmYuaGlnaCAqIDEwMCwKCiAgICAgICAgcGFydHlfbiA9IGZhY3RvcigKICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgICAiMiIsCiAgICAgICAgICAgICIzIiwKICAgICAgICAgICAgIjQiLAogICAgICAgICAgICAiNSIKICAgICAgICAgICksCiAgICAgICAgICBsYWJlbHMgPSBjKAogICAgICAgICAgICAiMumBuOaKnuiCoiIsCiAgICAgICAgICAgICIz6YG45oqe6IKiIiwKICAgICAgICAgICAgIjTpgbjmip7ogqIiLAogICAgICAgICAgICAiNemBuOaKnuiCoiIKICAgICAgICAgICkKICAgICAgICApLAoKICAgICAgICBhdHRyaWJ1dGUgPSBmYWN0b3IoCiAgICAgICAgICBhdHRyaWJ1dGUsCiAgICAgICAgICBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIKICAgICAgICApLAoKICAgICAgICBsYWJlbCA9IGZhY3RvcigKICAgICAgICAgIGxhYmVsLAogICAgICAgICAgbGV2ZWxzID0gcmV2KAogICAgICAgICAgICBsYWJlbF9vcmRlcgogICAgICAgICAgKQogICAgICAgICkKICAgICAgKQogIH0KCiAgYW1jZV9wbG90X25vY292IDwtIG1ha2VfYW1jZV9wbG90X2RmKAogICAgbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBhbWNlX3Bsb3Rfbm9jb3YsCiAgICAiYW1jZV9ub2Nvdl9jb2VmZmljaWVudHMuY3N2IgogICkKCiAgaW50ZXJhY3Rpb25fcGxvdF9kZiA8LSB0aWR5X2ZpeGVzdCgKICAgIG1faW50ZXJhY3Rpb24KICApICU+JQogICAgZmlsdGVyKAogICAgICBzdHJfZGV0ZWN0KAogICAgICAgIHRlcm0sCiAgICAgICAgInBhcnR5X25fZlszNDVdIgogICAgICApCiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBwYXJ0eV9uX2NvZGUgPSBzdHJfZXh0cmFjdCgKICAgICAgICB0ZXJtLAogICAgICAgICJwYXJ0eV9uX2ZbMzQ1XSIKICAgICAgKSwKCiAgICAgIHBhcnR5X24gPSBzdHJfcmVtb3ZlKAogICAgICAgIHBhcnR5X25fY29kZSwKICAgICAgICAicGFydHlfbl9mIgogICAgICApLAoKICAgICAgYmFzZV90ZXJtID0gdGVybSAlPiUKICAgICAgICBzdHJfcmVtb3ZlKAogICAgICAgICAgInBhcnR5X25fZlszNDVdOiIKICAgICAgICApICU+JQogICAgICAgIHN0cl9yZW1vdmUoCiAgICAgICAgICAiOnBhcnR5X25fZlszNDVdIgogICAgICAgICkKICAgICkgJT4lCiAgICBsZWZ0X2pvaW4oCiAgICAgIHRlcm1fbGFiZWxzLAogICAgICBieSA9IGMoCiAgICAgICAgImJhc2VfdGVybSIgPSAidGVybSIKICAgICAgKQogICAgKSAlPiUKICAgIGZpbHRlcigKICAgICAgIWlzLm5hKGF0dHJpYnV0ZSkKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGVzdGltYXRlX3BwID0gZXN0aW1hdGUgKiAxMDAsCiAgICAgIGNvbmYubG93X3BwID0gY29uZi5sb3cgKiAxMDAsCiAgICAgIGNvbmYuaGlnaF9wcCA9IGNvbmYuaGlnaCAqIDEwMCwKCiAgICAgIHBhcnR5X25fbGFiZWwgPSBmYWN0b3IoCiAgICAgICAgcGFydHlfbiwKICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgIjMiLAogICAgICAgICAgIjQiLAogICAgICAgICAgIjUiCiAgICAgICAgKSwKICAgICAgICBsYWJlbHMgPSBjKAogICAgICAgICAgIjPpgbjmip7ogqIiLAogICAgICAgICAgIjTpgbjmip7ogqIiLAogICAgICAgICAgIjXpgbjmip7ogqIiCiAgICAgICAgKQogICAgICApLAoKICAgICAgYXR0cmlidXRlID0gZmFjdG9yKAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIKICAgICAgKSwKCiAgICAgIGxhYmVsID0gZmFjdG9yKAogICAgICAgIGxhYmVsLAogICAgICAgIGxldmVscyA9IHJldigKICAgICAgICAgIGxhYmVsX29yZGVyCiAgICAgICAgKQogICAgICApCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBpbnRlcmFjdGlvbl9wbG90X2RmLAogICAgImFtY2VfaW50ZXJhY3Rpb25fY29lZmZpY2llbnRzLmNzdiIKICApCgogIGxpbmVhcl90cmVuZF9wbG90X2RmIDwtIHRpZHlfZml4ZXN0KAogICAgbV9saW5lYXJfdHJlbmQKICApICU+JQogICAgZmlsdGVyKAogICAgICBzdHJfZGV0ZWN0KAogICAgICAgIHRlcm0sCiAgICAgICAgInBhcnR5X25fYzoiCiAgICAgICkgfAogICAgICAgIHN0cl9kZXRlY3QoCiAgICAgICAgICB0ZXJtLAogICAgICAgICAgIjpwYXJ0eV9uX2MiCiAgICAgICAgKQogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgYmFzZV90ZXJtID0gdGVybSAlPiUKICAgICAgICBzdHJfcmVtb3ZlKAogICAgICAgICAgInBhcnR5X25fYzoiCiAgICAgICAgKSAlPiUKICAgICAgICBzdHJfcmVtb3ZlKAogICAgICAgICAgIjpwYXJ0eV9uX2MiCiAgICAgICAgKQogICAgKSAlPiUKICAgIGxlZnRfam9pbigKICAgICAgdGVybV9sYWJlbHMsCiAgICAgIGJ5ID0gYygKICAgICAgICAiYmFzZV90ZXJtIiA9ICJ0ZXJtIgogICAgICApCiAgICApICU+JQogICAgZmlsdGVyKAogICAgICAhaXMubmEoYXR0cmlidXRlKQogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAoKICAgICAgYXR0cmlidXRlID0gZmFjdG9yKAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIKICAgICAgKSwKCiAgICAgIGxhYmVsID0gZmFjdG9yKAogICAgICAgIGxhYmVsLAogICAgICAgIGxldmVscyA9IHJldigKICAgICAgICAgIGxhYmVsX29yZGVyCiAgICAgICAgKQogICAgICApCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBsaW5lYXJfdHJlbmRfcGxvdF9kZiwKICAgICJhbWNlX2xpbmVhcl90cmVuZF9jb2VmZmljaWVudHMuY3N2IgogICkKCgogIHJlY29kZV9mZW1hbGVfc3R1ZHkzIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHhfbnVtIDwtIGFzX251bSh4KQoKICAgIGNhc2Vfd2hlbigKICAgICAgeF9udW0gPT0gMiB+IDFMLAogICAgICB4X251bSA9PSAxIH4gMEwsCiAgICAgIFRSVUUgfiBOQV9pbnRlZ2VyXwogICAgKQogIH0KCiAgcmVjb2RlX2NvbGxlZ2VfZ3JhZF9zdHVkeTMgPC0gZnVuY3Rpb24oeCkgewogICAgeF9udW0gPC0gYXNfbnVtKHgpCgogICAgY2FzZV93aGVuKAogICAgICB4X251bSAlaW4lIGMoCiAgICAgICAgNCwKICAgICAgICA1CiAgICAgICkgfiAxTCwKCiAgICAgIHhfbnVtICVpbiUgYygKICAgICAgICAxLAogICAgICAgIDIsCiAgICAgICAgMwogICAgICApIH4gMEwsCgogICAgICBUUlVFIH4gTkFfaW50ZWdlcl8KICAgICkKICB9CgogIHJlY29kZV9zZWxmX2lkZW9sb2d5X3N0dWR5MyA8LSBmdW5jdGlvbih4KSB7CiAgICB4X251bSA8LSBhc19udW0oeCkKCiAgICBjYXNlX3doZW4oCiAgICAgIHhfbnVtICVpbiUgMTo4IH4geF9udW0sCiAgICAgIHhfbnVtID09IDEyIH4gOSwKICAgICAgeF9udW0gPT0gMTMgfiAxMCwKICAgICAgeF9udW0gPT0gMTQgfiAxMSwKICAgICAgVFJVRSB+IE5BX3JlYWxfCiAgICApCiAgfQoKICByZWNvZGVfcGFydHlfc3VwcG9ydF9zdHVkeTMgPC0gZnVuY3Rpb24oeCkgewogICAgeF9udW0gPC0gYXNfbnVtKHgpCgogICAgY2FzZV93aGVuKAogICAgICB4X251bSA9PSAxIH4gIuiHqueUseawkeS4u+WFmiIsCiAgICAgIHhfbnVtID09IDIgfiAi5Lit6YGT5pS56Z2p6YCj5ZCIIiwKICAgICAgeF9udW0gPT0gMyB+ICLnq4vmhrLmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSA0IH4gIuWFrOaYjuWFmiIsCiAgICAgIHhfbnVtID09IDUgfiAi5pel5pys57at5paw44Gu5LyaIiwKICAgICAgeF9udW0gPT0gNiB+ICLlm73msJHmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSA3IH4gIuOCjOOBhOOCj+aWsOmBuOe1hCIsCiAgICAgIHhfbnVtID09IDggfiAi5pel5pys5YWx55Sj5YWaIiwKICAgICAgeF9udW0gPT0gOSB+ICLlj4LmlL/lhZoiLAogICAgICB4X251bSA9PSAxMCB+ICLml6XmnKzkv53lrojlhZoiLAogICAgICB4X251bSA9PSAxMSB+ICLnpL7kvJrmsJHkuLvlhZoiLAogICAgICB4X251bSA9PSAxMiB+ICLjg4Hjg7zjg6Djgb/jgonjgYQiLAogICAgICB4X251bSA9PSAxMyB+ICLjgZ3jga7ku5YiLAogICAgICB4X251bSA9PSAxNCB+ICLmlK/mjIHmlL/lhZrjgarjgZciLAogICAgICB4X251bSA9PSAxNSB+ICLjgo/jgYvjgonjgarjgYQiLAogICAgICB4X251bSA9PSAxNiB+ICLnrZTjgYjjgZ/jgY/jgarjgYQiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogIH0KCiAgZ2VuZGVyX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKAogICAgICAiUTIuMSIsCiAgICAgICJRMl8xIgogICAgKQogICkKCiAgYWdlX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKAogICAgICAiUTIuMl8xMyIsCiAgICAgICJRMi4yLjEzIiwKICAgICAgIlEyXzJfMTMiLAogICAgICAiUTIuMl8yIiwKICAgICAgIlEyLjIuMiIsCiAgICAgICJRMl8yXzIiCiAgICApCiAgKQoKICBlZHVjYXRpb25fcmF3IDwtIGdldF92YXIoCiAgICBkZiwKICAgIGMoCiAgICAgICJRMi4zIiwKICAgICAgIlEyXzMiCiAgICApCiAgKQoKICByZWdpb25fcmF3IDwtIGdldF92YXIoCiAgICBkZiwKICAgIGMoCiAgICAgICJRMi40XzEiLAogICAgICAiUTIuNC4xIiwKICAgICAgIlEyXzRfMSIKICAgICkKICApCgogIHByZWZlY3R1cmVfcmF3IDwtIGdldF92YXIoCiAgICBkZiwKICAgIGMoCiAgICAgICJRMi40XzIiLAogICAgICAiUTIuNC4yIiwKICAgICAgIlEyXzRfMiIKICAgICkKICApCgogIGluY29tZV9ncm9zc19yYXcgPC0gZ2V0X3ZhcigKICAgIGRmLAogICAgYygKICAgICAgIlEyLjVfMSIsCiAgICAgICJRMi41LjEiLAogICAgICAiUTJfNV8xIgogICAgKQogICkKCiAgaW5jb21lX25ldF9yYXcgPC0gZ2V0X3ZhcigKICAgIGRmLAogICAgYygKICAgICAgIlEyLjVfMiIsCiAgICAgICJRMi41LjIiLAogICAgICAiUTJfNV8yIgogICAgKQogICkKCiAgemVyb19pbmNvbWVfcmVhc29uX3JhdyA8LSBnZXRfdmFyKAogICAgZGYsCiAgICBjKAogICAgICAiUTIuNiIsCiAgICAgICJRMl82IgogICAgKQogICkKCiAgc2VsZl9pZGVvbG9neV9yYXcgPC0gZ2V0X3ZhcigKICAgIGRmLAogICAgYygKICAgICAgIlEyNS4xXzEiLAogICAgICAiUTI1LjEuMSIsCiAgICAgICJRMjVfMV8xIgogICAgKQogICkKCiAgcGFydHlfc3VwcG9ydF9yYXcgPC0gZ2V0X3ZhcigKICAgIGRmLAogICAgYygKICAgICAgIlE3LjIiLAogICAgICAiUTdfMiIKICAgICkKICApCgogIGNvdmFyX2lkIDwtIGRmICU+JQogICAgdHJhbnNtdXRlKAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihSZXNwb25zZUlkKSwKCiAgICAgIGZlbWFsZSA9IHJlY29kZV9mZW1hbGVfc3R1ZHkzKAogICAgICAgIGdlbmRlcl9yYXcKICAgICAgKSwKCiAgICAgIGFnZSA9IGFzX251bSgKICAgICAgICBhZ2VfcmF3CiAgICAgICksCgogICAgICBjb2xsZWdlX2dyYWQgPSByZWNvZGVfY29sbGVnZV9ncmFkX3N0dWR5MygKICAgICAgICBlZHVjYXRpb25fcmF3CiAgICAgICksCgogICAgICByZWdpb24gPSBmYWN0b3JfbWlzcygKICAgICAgICByZWdpb25fcmF3CiAgICAgICksCgogICAgICBwcmVmZWN0dXJlID0gZmFjdG9yX21pc3MoCiAgICAgICAgcHJlZmVjdHVyZV9yYXcKICAgICAgKSwKCiAgICAgIGluY29tZV9ncm9zcyA9IGFzX251bSgKICAgICAgICBpbmNvbWVfZ3Jvc3NfcmF3CiAgICAgICksCgogICAgICBpbmNvbWVfbmV0ID0gYXNfbnVtKAogICAgICAgIGluY29tZV9uZXRfcmF3CiAgICAgICksCgogICAgICBpbmNvbWVfZ3Jvc3NfbG9nID0gbG9nMXAoCiAgICAgICAgaW5jb21lX2dyb3NzCiAgICAgICksCgogICAgICBpbmNvbWVfbmV0X2xvZyA9IGxvZzFwKAogICAgICAgIGluY29tZV9uZXQKICAgICAgKSwKCiAgICAgIHplcm9faW5jb21lX3JlYXNvbiA9IGZhY3Rvcl9taXNzKAogICAgICAgIHplcm9faW5jb21lX3JlYXNvbl9yYXcKICAgICAgKSwKCiAgICAgIHNlbGZfaWRlb2xvZ3kgPSByZWNvZGVfc2VsZl9pZGVvbG9neV9zdHVkeTMoCiAgICAgICAgc2VsZl9pZGVvbG9neV9yYXcKICAgICAgKSwKCiAgICAgIHBhcnR5X3N1cHBvcnQgPSByZWNvZGVfcGFydHlfc3VwcG9ydF9zdHVkeTMoCiAgICAgICAgcGFydHlfc3VwcG9ydF9yYXcKICAgICAgKSwKCiAgICAgIHBhcnR5X3N1cHBvcnRfZiA9IGZhY3Rvcl9taXNzKAogICAgICAgIHBhcnR5X3N1cHBvcnQKICAgICAgKSwKCiAgICAgIHBhcnR5X3N1cHBvcnRfcHJvZmlsZSA9IGNhbm9uaWNhbGl6ZV9wYXJ0eV9uYW1lKAogICAgICAgIHBhcnR5X3N1cHBvcnQKICAgICAgKQogICAgKSAlPiUKICAgIHNlbWlfam9pbigKICAgICAgdmFsaWRfaWRzICU+JQogICAgICAgIHNlbGVjdChJRCksCiAgICAgIGJ5ID0gIklEIgogICAgKSAlPiUKICAgIGRpc3RpbmN0KAogICAgICBJRCwKICAgICAgLmtlZXBfYWxsID0gVFJVRQogICAgKQoKICBjb3Zhcl9pZCA8LSBjb3Zhcl9pZCAlPiUKICAgIG11dGF0ZSgKICAgICAgYWdlID0gaWZfZWxzZSgKICAgICAgICBhZ2UgPj0gMTggJgogICAgICAgICAgYWdlIDw9IDc5LAogICAgICAgIGFnZSwKICAgICAgICBOQV9yZWFsXwogICAgICApCiAgICApCgogIGFnZV9pbXBfb2JqIDwtIG1lYW5faW1wdXRlKAogICAgY292YXJfaWQkYWdlCiAgKQoKICBpbmNvbWVfZ3Jvc3NfaW1wX29iaiA8LSBtZWFuX2ltcHV0ZSgKICAgIGNvdmFyX2lkJGluY29tZV9ncm9zc19sb2cKICApCgogIHNlbGZfaWRlb2xvZ3lfaW1wX29iaiA8LSBtZWFuX2ltcHV0ZSgKICAgIGNvdmFyX2lkJHNlbGZfaWRlb2xvZ3kKICApCgogIGNvdmFyX2lkIDwtIGNvdmFyX2lkICU+JQogICAgbXV0YXRlKAogICAgICBmZW1hbGVfaW1wID0gaWZfZWxzZSgKICAgICAgICBpcy5uYShmZW1hbGUpLAogICAgICAgIDBMLAogICAgICAgIGZlbWFsZQogICAgICApLAoKICAgICAgZmVtYWxlX21pc3MgPSBhcy5pbnRlZ2VyKAogICAgICAgIGlzLm5hKGZlbWFsZSkKICAgICAgKSwKCiAgICAgIGNvbGxlZ2VfZ3JhZF9pbXAgPSBpZl9lbHNlKAogICAgICAgIGlzLm5hKGNvbGxlZ2VfZ3JhZCksCiAgICAgICAgMEwsCiAgICAgICAgY29sbGVnZV9ncmFkCiAgICAgICksCgogICAgICBjb2xsZWdlX2dyYWRfbWlzcyA9IGFzLmludGVnZXIoCiAgICAgICAgaXMubmEoY29sbGVnZV9ncmFkKQogICAgICApLAoKICAgICAgYWdlX2ltcCA9IGFnZV9pbXBfb2JqJHZhbHVlLAoKICAgICAgYWdlX21pc3MgPSBhZ2VfaW1wX29iaiRtaXNzLAoKICAgICAgaW5jb21lX2dyb3NzX2xvZ19pbXAgPQogICAgICAgIGluY29tZV9ncm9zc19pbXBfb2JqJHZhbHVlLAoKICAgICAgaW5jb21lX2dyb3NzX2xvZ19taXNzID0KICAgICAgICBpbmNvbWVfZ3Jvc3NfaW1wX29iaiRtaXNzLAoKICAgICAgc2VsZl9pZGVvbG9neV9pbXAgPQogICAgICAgIHNlbGZfaWRlb2xvZ3lfaW1wX29iaiR2YWx1ZSwKCiAgICAgIHNlbGZfaWRlb2xvZ3lfbWlzcyA9CiAgICAgICAgc2VsZl9pZGVvbG9neV9pbXBfb2JqJG1pc3MKICAgICkKCiAgY292YXJpYXRlX21pc3Npbmdfc3VtbWFyeSA8LSBjb3Zhcl9pZCAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbl9pZHMgPSBuX2Rpc3RpbmN0KElEKSwKICAgICAgZmVtYWxlX21pc3NpbmcgPSBzdW0oCiAgICAgICAgaXMubmEoZmVtYWxlKQogICAgICApLAogICAgICBhZ2VfbWlzc2luZyA9IHN1bSgKICAgICAgICBpcy5uYShhZ2UpCiAgICAgICksCiAgICAgIGNvbGxlZ2VfZ3JhZF9taXNzaW5nID0gc3VtKAogICAgICAgIGlzLm5hKGNvbGxlZ2VfZ3JhZCkKICAgICAgKSwKICAgICAgaW5jb21lX2dyb3NzX21pc3NpbmcgPSBzdW0oCiAgICAgICAgaXMubmEoaW5jb21lX2dyb3NzX2xvZykKICAgICAgKSwKICAgICAgc2VsZl9pZGVvbG9neV9taXNzaW5nID0gc3VtKAogICAgICAgIGlzLm5hKHNlbGZfaWRlb2xvZ3kpCiAgICAgICksCiAgICAgIHBhcnR5X3N1cHBvcnRfbWlzc2luZyA9IHN1bSgKICAgICAgICBpcy5uYShwYXJ0eV9zdXBwb3J0KQogICAgICApCiAgICApCgogIHplcm9faW5jb21lX3N1bW1hcnkgPC0gY292YXJfaWQgJT4lCiAgICBjb3VudCgKICAgICAgemVyb19pbmNvbWVfcmVhc29uLAogICAgICBuYW1lID0gIm4iCiAgICApICU+JQogICAgYXJyYW5nZSgKICAgICAgZGVzYyhuKQogICAgKQoKICBwcmludChjb3ZhcmlhdGVfbWlzc2luZ19zdW1tYXJ5KQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgY292YXJfaWQsCiAgICAicmVzcG9uZGVudF9jb3ZhcmlhdGVzLmNzdiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBjb3ZhcmlhdGVfbWlzc2luZ19zdW1tYXJ5LAogICAgImNvdmFyaWF0ZV9taXNzaW5nX3N1bW1hcnkuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHplcm9faW5jb21lX3N1bW1hcnksCiAgICAiemVyb19pbmNvbWVfcmVhc29uX3N1bW1hcnkuY3N2IgogICkKCgogIGNvbmpvaW50X2FsbF9jb3YgPC0gY29uam9pbnRfYWxsX20gJT4lCiAgICBsZWZ0X2pvaW4oCiAgICAgIGNvdmFyX2lkLAogICAgICBieSA9ICJJRCIKICAgICkKCiAgY292YXJpYXRlX3Rlcm1zIDwtIGMoCiAgICAiZmVtYWxlX2ltcCIsCiAgICAiZmVtYWxlX21pc3MiLAogICAgImFnZV9pbXAiLAogICAgImFnZV9taXNzIiwKICAgICJjb2xsZWdlX2dyYWRfaW1wIiwKICAgICJjb2xsZWdlX2dyYWRfbWlzcyIsCiAgICAiaW5jb21lX2dyb3NzX2xvZ19pbXAiLAogICAgImluY29tZV9ncm9zc19sb2dfbWlzcyIsCiAgICAic2VsZl9pZGVvbG9neV9pbXAiLAogICAgInNlbGZfaWRlb2xvZ3lfbWlzcyIsCiAgICAicGFydHlfc3VwcG9ydF9mIgogICkKCiAgaGFzX3ZhcmlhdGlvbiA8LSBmdW5jdGlvbihkYXQsIHYpIHsKICAgIGlmICghdiAlaW4lIG5hbWVzKGRhdCkpIHsKICAgICAgcmV0dXJuKEZBTFNFKQogICAgfQoKICAgIGRwbHlyOjpuX2Rpc3RpbmN0KAogICAgICBkYXRbW3ZdXSwKICAgICAgbmEucm0gPSBUUlVFCiAgICApID4gMQogIH0KCiAgY292YXJpYXRlX3Rlcm1zX3VzZSA8LSBjb3ZhcmlhdGVfdGVybXNbCiAgICBtYXBfbGdsKAogICAgICBjb3ZhcmlhdGVfdGVybXMsCiAgICAgIH4gaGFzX3ZhcmlhdGlvbigKICAgICAgICBjb25qb2ludF9hbGxfY292LAogICAgICAgIC54CiAgICAgICkKICAgICkKICBdCgogIGZvcm11bGFfY292IDwtIGFzLmZvcm11bGEoCiAgICBwYXN0ZSgKICAgICAgInNlbGVjdGVkIH4iLAogICAgICBwYXN0ZSgKICAgICAgICBjKAogICAgICAgICAgYXR0cl90ZXJtcywKICAgICAgICAgIGNvdmFyaWF0ZV90ZXJtc191c2UKICAgICAgICApLAogICAgICAgIGNvbGxhcHNlID0gIiArICIKICAgICAgKQogICAgKQogICkKCiAgcnVuX2FtY2VfY292IDwtIGZ1bmN0aW9uKGRhdCkgewogICAgZmVvbHMoCiAgICAgIGZvcm11bGFfY292LAogICAgICBkYXRhID0gZGF0LAogICAgICB2Y292ID0gfiBJRAogICAgKQogIH0KCiAgbW9kZWxzX2J5X3BhcnR5X25fY292IDwtIGNvbmpvaW50X2FsbF9jb3YgJT4lCiAgICBzcGxpdCguJHBhcnR5X24pICU+JQogICAgbWFwKHJ1bl9hbWNlX2NvdikKCiAgY2FwdHVyZS5vdXRwdXQoCiAgICBldGFibGUoCiAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX25vY292LAogICAgICBtb2RlbHNfYnlfcGFydHlfbl9jb3YsCiAgICAgIGhlYWRlcnMgPSBjKAogICAgICAgIHJlcCgKICAgICAgICAgICLlhbHlpInph4/jgarjgZciLAogICAgICAgICAgbGVuZ3RoKAogICAgICAgICAgICBtb2RlbHNfYnlfcGFydHlfbl9ub2NvdgogICAgICAgICAgKQogICAgICAgICksCiAgICAgICAgcmVwKAogICAgICAgICAgIuWFseWkiemHj+OBguOCiiIsCiAgICAgICAgICBsZW5ndGgoCiAgICAgICAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX2NvdgogICAgICAgICAgKQogICAgICAgICkKICAgICAgKQogICAgKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJhbWNlX25vY292X2FuZF9jb3ZfbW9kZWxzLnR4dCIKICAgICkKICApCgogIGFtY2VfcGxvdF9jb3YgPC0gbWFrZV9hbWNlX3Bsb3RfZGYoCiAgICBtb2RlbHNfYnlfcGFydHlfbl9jb3YKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBhbWNlX3Bsb3RfY292LAogICAgImFtY2VfY292X2NvZWZmaWNpZW50cy5jc3YiCiAgKQoKCiAgc3R1ZHlfbGFiZWwgPC0gIuWun+mokzPvvIgyMDI25bm077yJIgoKICBwX2FtY2VfY292IDwtIGdncGxvdCgKICAgIGFtY2VfcGxvdF9jb3YsCiAgICBhZXMoCiAgICAgIHggPSBlc3RpbWF0ZV9wcCwKICAgICAgeSA9IGxhYmVsLAogICAgICBzaGFwZSA9IHBhcnR5X24sCiAgICAgIGxpbmV0eXBlID0gcGFydHlfbiwKICAgICAgZ3JvdXAgPSBwYXJ0eV9uCiAgICApCiAgKSArCiAgICBnZW9tX3ZsaW5lKAogICAgICB4aW50ZXJjZXB0ID0gMCwKICAgICAgbGluZXdpZHRoID0gMC40NSwKICAgICAgY29sb3IgPSAiZ3JleTM1IgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyaCgKICAgICAgYWVzKAogICAgICAgIHhtaW4gPSBjb25mLmxvd19wcCwKICAgICAgICB4bWF4ID0gY29uZi5oaWdoX3BwCiAgICAgICksCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoCiAgICAgICAgd2lkdGggPSAwLjY1CiAgICAgICksCiAgICAgIGhlaWdodCA9IDAuMTYsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX3BvaW50KAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKAogICAgICAgIHdpZHRoID0gMC42NQogICAgICApLAogICAgICBzaXplID0gMi41LAogICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBzdHJva2UgPSAwLjgKICAgICkgKwogICAgZmFjZXRfZ3JpZCgKICAgICAgYXR0cmlidXRlIH4gLiwKICAgICAgc2NhbGVzID0gImZyZWVfeSIsCiAgICAgIHNwYWNlID0gImZyZWVfeSIsCiAgICAgIHN3aXRjaCA9ICJ5IgogICAgKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICBwYXN0ZTAoeCwgIiBwcCIpCiAgICAgIH0sCiAgICAgIGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcygKICAgICAgICBuID0gOAogICAgICApCiAgICApICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICLpgbjmip7ogqLmlbAiLAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICIy6YG45oqe6IKiIiA9IDE2LAogICAgICAgICIz6YG45oqe6IKiIiA9IDE3LAogICAgICAgICI06YG45oqe6IKiIiA9IDE1LAogICAgICAgICI16YG45oqe6IKiIiA9IDEKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAi6YG45oqe6IKi5pWwIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMumBuOaKnuiCoiIgPSAic29saWQiLAogICAgICAgICIz6YG45oqe6IKiIiA9ICJkYXNoZWQiLAogICAgICAgICI06YG45oqe6IKiIiA9ICJkb3R0ZWQiLAogICAgICAgICI16YG45oqe6IKiIiA9ICJkb3RkYXNoIgogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAgICLmlL/lhZrlkI3jga7ln7rmupbjgqvjg4bjgrTjg6rvvJoiLAogICAgICAgIHBhcnR5X3JlZmVyZW5jZSwKICAgICAgICAi44CC57WM5riI5bGe5oCn44Gv5aSJ5YyW44Gq44GX44KS5Z+65rqW44Go44GZ44KL44CCIgogICAgICApLAogICAgICB4ID0gIumBuOaKnueiuueOh+OBruWkieWMliIsCiAgICAgIHkgPSBOVUxMCiAgICApICsKICAgIHRoZW1lX2J3KAogICAgICBiYXNlX3NpemUgPSAxMiwKICAgICAgYmFzZV9mYW1pbHkgPSBmaWd1cmVfZm9udF9mYW1pbHkKICAgICkgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTYKICAgICAgKSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiCiAgICAgICksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KAogICAgICAgIGZpbGwgPSAiZ3JleTkyIiwKICAgICAgICBjb2xvciA9ICJncmV5NTUiCiAgICAgICksCiAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGFuZ2xlID0gMCwKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxMAogICAgICApLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gOQogICAgICApLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIgogICAgICApCiAgICApCgogIHByaW50KHBfYW1jZV9jb3YpCgogIHNhdmVfcGxvdCgKICAgICJhbWNlX2Nvdl9mYWNldF9tb2RlbC5wbmciLAogICAgcF9hbWNlX2NvdiwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDExLjUKICApCgoKICBwX2FtY2Vfbm9jb3YgPC0gZ2dwbG90KAogICAgYW1jZV9wbG90X25vY292LAogICAgYWVzKAogICAgICB4ID0gZXN0aW1hdGVfcHAsCiAgICAgIHkgPSBsYWJlbCwKICAgICAgc2hhcGUgPSBwYXJ0eV9uLAogICAgICBsaW5ldHlwZSA9IHBhcnR5X24sCiAgICAgIGdyb3VwID0gcGFydHlfbgogICAgKQogICkgKwogICAgZ2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImdyZXkzNSIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcmgoCiAgICAgIGFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKAogICAgICAgIHdpZHRoID0gMC42NQogICAgICApLAogICAgICBoZWlnaHQgPSAwLjE2LAogICAgICBsaW5ld2lkdGggPSAwLjU1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgKICAgICAgICB3aWR0aCA9IDAuNjUKICAgICAgKSwKICAgICAgc2l6ZSA9IDIuNSwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgc3Ryb2tlID0gMC44CiAgICApICsKICAgIGZhY2V0X2dyaWQoCiAgICAgIGF0dHJpYnV0ZSB+IC4sCiAgICAgIHNjYWxlcyA9ICJmcmVlX3kiLAogICAgICBzcGFjZSA9ICJmcmVlX3kiLAogICAgICBzd2l0Y2ggPSAieSIKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgcGFzdGUwKHgsICIgcHAiKQogICAgICB9LAogICAgICBicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MoCiAgICAgICAgbiA9IDgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAi6YG45oqe6IKi5pWwIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMumBuOaKnuiCoiIgPSAxNiwKICAgICAgICAiM+mBuOaKnuiCoiIgPSAxNywKICAgICAgICAiNOmBuOaKnuiCoiIgPSAxNSwKICAgICAgICAiNemBuOaKnuiCoiIgPSAxCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICBuYW1lID0gIumBuOaKnuiCouaVsCIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLpgbjmip7ogqIiID0gInNvbGlkIiwKICAgICAgICAiM+mBuOaKnuiCoiIgPSAiZGFzaGVkIiwKICAgICAgICAiNOmBuOaKnuiCoiIgPSAiZG90dGVkIiwKICAgICAgICAiNemBuOaKnuiCoiIgPSAiZG90ZGFzaCIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgKICAgICAgICAi5pS/5YWa5ZCN44Gu5Z+65rqW44Kr44OG44K044Oq77yaIiwKICAgICAgICBwYXJ0eV9yZWZlcmVuY2UsCiAgICAgICAgIuOAgue1jOa4iOWxnuaAp+OBr+WkieWMluOBquOBl+OCkuWfuua6luOBqOOBmeOCi+OAgiIKICAgICAgKSwKICAgICAgeCA9ICLpgbjmip7norrnjofjga7lpInljJYiLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idygKICAgICAgYmFzZV9zaXplID0gMTIsCiAgICAgIGJhc2VfZmFtaWx5ID0gZmlndXJlX2ZvbnRfZmFtaWx5CiAgICApICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgc2l6ZSA9IDE2CiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDEwCiAgICAgICksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIgogICAgICApLAogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDkKICAgICAgKSwKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIKICAgICAgKQogICAgKQoKICBwcmludChwX2FtY2Vfbm9jb3YpCgogIHNhdmVfcGxvdCgKICAgICJhbWNlX25vY292X2ZhY2V0X21vZGVsLnBuZyIsCiAgICBwX2FtY2Vfbm9jb3YsCiAgICB3aWR0aCA9IDEwLjUsCiAgICBoZWlnaHQgPSAxMS41CiAgKQoKCiAgcF9pbnRlcmFjdGlvbiA8LSBnZ3Bsb3QoCiAgICBpbnRlcmFjdGlvbl9wbG90X2RmLAogICAgYWVzKAogICAgICB4ID0gZXN0aW1hdGVfcHAsCiAgICAgIHkgPSBsYWJlbCwKICAgICAgc2hhcGUgPSBwYXJ0eV9uX2xhYmVsLAogICAgICBsaW5ldHlwZSA9IHBhcnR5X25fbGFiZWwsCiAgICAgIGdyb3VwID0gcGFydHlfbl9sYWJlbAogICAgKQogICkgKwogICAgZ2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImdyZXkzNSIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcmgoCiAgICAgIGFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKAogICAgICAgIHdpZHRoID0gMC42NQogICAgICApLAogICAgICBoZWlnaHQgPSAwLjE2LAogICAgICBsaW5ld2lkdGggPSAwLjU1LAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgKICAgICAgICB3aWR0aCA9IDAuNjUKICAgICAgKSwKICAgICAgc2l6ZSA9IDIuNSwKICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgc3Ryb2tlID0gMC44CiAgICApICsKICAgIGZhY2V0X2dyaWQoCiAgICAgIGF0dHJpYnV0ZSB+IC4sCiAgICAgIHNjYWxlcyA9ICJmcmVlX3kiLAogICAgICBzcGFjZSA9ICJmcmVlX3kiLAogICAgICBzd2l0Y2ggPSAieSIKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgcGFzdGUwKHgsICIgcHAiKQogICAgICB9LAogICAgICBicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MoCiAgICAgICAgbiA9IDgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIG5hbWUgPSAiMumBuOaKnuiCouadoeS7tuOBqOOBruavlOi8gyIsCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjPpgbjmip7ogqIiID0gMTcsCiAgICAgICAgIjTpgbjmip7ogqIiID0gMTUsCiAgICAgICAgIjXpgbjmip7ogqIiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgbmFtZSA9ICIy6YG45oqe6IKi5p2h5Lu244Go44Gu5q+U6LyDIiwKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiM+mBuOaKnuiCoiIgPSAiZGFzaGVkIiwKICAgICAgICAiNOmBuOaKnuiCoiIgPSAiZG90dGVkIiwKICAgICAgICAiNemBuOaKnuiCoiIgPSAiZG90ZGFzaCIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB4ID0gIjLpgbjmip7ogqLmnaHku7bjgajjga7lt64iLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idygKICAgICAgYmFzZV9zaXplID0gMTIsCiAgICAgIGJhc2VfZmFtaWx5ID0gZmlndXJlX2ZvbnRfZmFtaWx5CiAgICApICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgc2l6ZSA9IDE1CiAgICAgICksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIgogICAgICApLAogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICBzaXplID0gMTAKICAgICAgKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDkKICAgICAgKSwKICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIKICAgICAgKQogICAgKQoKICBwcmludChwX2ludGVyYWN0aW9uKQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9pbnRlcmFjdGlvbl9kaWZmZXJlbmNlX2Zyb21fMmNob2ljZS5wbmciLAogICAgcF9pbnRlcmFjdGlvbiwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDExLjUKICApCgoKICBwX2xpbmVhcl90cmVuZCA8LSBnZ3Bsb3QoCiAgICBsaW5lYXJfdHJlbmRfcGxvdF9kZiwKICAgIGFlcygKICAgICAgeCA9IGVzdGltYXRlX3BwLAogICAgICB5ID0gbGFiZWwKICAgICkKICApICsKICAgIGdlb21fdmxpbmUoCiAgICAgIHhpbnRlcmNlcHQgPSAwLAogICAgICBsaW5ld2lkdGggPSAwLjQ1LAogICAgICBjb2xvciA9ICJncmV5MzUiCiAgICApICsKICAgIGdlb21fZXJyb3JiYXJoKAogICAgICBhZXMoCiAgICAgICAgeG1pbiA9IGNvbmYubG93X3BwLAogICAgICAgIHhtYXggPSBjb25mLmhpZ2hfcHAKICAgICAgKSwKICAgICAgaGVpZ2h0ID0gMC4xNiwKICAgICAgbGluZXdpZHRoID0gMC41NSwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fcG9pbnQoCiAgICAgIHNpemUgPSAyLjUsCiAgICAgIHNoYXBlID0gMjEsCiAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIHN0cm9rZSA9IDAuOAogICAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBhdHRyaWJ1dGUgfiAuLAogICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgc3BhY2UgPSAiZnJlZV95IiwKICAgICAgc3dpdGNoID0gInkiCiAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgewogICAgICAgIHBhc3RlMCh4LCAiIHBwIikKICAgICAgfSwKICAgICAgYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKAogICAgICAgIG4gPSA4CiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgc3VidGl0bGUgPSAi5qiq6Lu444Gv44CB6YG45oqe6IKi5pWw44GMMeOBpOWil+OBiOOBn+OBqOOBjeOBruWxnuaAp+WKueaenOOBruWkieWMliIsCiAgICAgIHggPSAiMemBuOaKnuiCouWil+WKoOW9k+OBn+OCiuOBrkFNQ0XlpInljJYiLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idygKICAgICAgYmFzZV9zaXplID0gMTIsCiAgICAgIGJhc2VfZmFtaWx5ID0gZmlndXJlX2ZvbnRfZmFtaWx5CiAgICApICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgc2l6ZSA9IDE1CiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDEwCiAgICAgICksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KAogICAgICAgIGZpbGwgPSAiZ3JleTkyIiwKICAgICAgICBjb2xvciA9ICJncmV5NTUiCiAgICAgICksCiAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGFuZ2xlID0gMCwKICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgIHNpemUgPSAxMAogICAgICApLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gOQogICAgICApLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoCiAgICAgICAgZmFjZSA9ICJib2xkIgogICAgICApCiAgICApCgogIHByaW50KHBfbGluZWFyX3RyZW5kKQoKICBzYXZlX3Bsb3QoCiAgICAiYW1jZV9saW5lYXJfdHJlbmQucG5nIiwKICAgIHBfbGluZWFyX3RyZW5kLAogICAgd2lkdGggPSAxMC41LAogICAgaGVpZ2h0ID0gMTEuNQogICkKCgogIGhlYXRtYXBfZGYgPC0gYW1jZV9wbG90X2NvdiAlPiUKICAgIG11dGF0ZSgKICAgICAgYWJzX2FtY2UgPSBhYnMoCiAgICAgICAgZXN0aW1hdGVfcHAKICAgICAgKQogICAgKSAlPiUKICAgIGdyb3VwX2J5KHBhcnR5X24pICU+JQogICAgbXV0YXRlKAogICAgICByYW5rX3dpdGhpbl9jb25kaXRpb24gPQogICAgICAgIG1pbl9yYW5rKAogICAgICAgICAgZGVzYyhhYnNfYW1jZSkKICAgICAgICApLAoKICAgICAgbl9pbl9jb25kaXRpb24gPSBuKCksCgogICAgICByYW5rX3Njb3JlID0gaWZfZWxzZSgKICAgICAgICBuX2luX2NvbmRpdGlvbiA9PSAxLAogICAgICAgIDEsCiAgICAgICAgMSAtCiAgICAgICAgICAoCiAgICAgICAgICAgIHJhbmtfd2l0aGluX2NvbmRpdGlvbiAtIDEKICAgICAgICAgICkgLwogICAgICAgICAgKAogICAgICAgICAgICBuX2luX2NvbmRpdGlvbiAtIDEKICAgICAgICAgICkKICAgICAgKQogICAgKSAlPiUKICAgIHVuZ3JvdXAoKQoKICBoZWF0bWFwX3Jvd19vcmRlciA8LSBoZWF0bWFwX2RmICU+JQogICAgZ3JvdXBfYnkoCiAgICAgIGxhYmVsLAogICAgICBhdHRyaWJ1dGUKICAgICkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG1lYW5fYWJzX2FtY2UgPSBtZWFuKAogICAgICAgIGFic19hbWNlLAogICAgICAgIG5hLnJtID0gVFJVRQogICAgICApLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApICU+JQogICAgYXJyYW5nZSgKICAgICAgZGVzYyhtZWFuX2Fic19hbWNlKQogICAgKSAlPiUKICAgIHB1bGwobGFiZWwpICU+JQogICAgYXMuY2hhcmFjdGVyKCkKCiAgaGVhdG1hcF9kZiA8LSBoZWF0bWFwX2RmICU+JQogICAgbXV0YXRlKAogICAgICBsYWJlbF9oZWF0ID0gZmFjdG9yKAogICAgICAgIGFzLmNoYXJhY3RlcihsYWJlbCksCiAgICAgICAgbGV2ZWxzID0gcmV2KAogICAgICAgICAgaGVhdG1hcF9yb3dfb3JkZXIKICAgICAgICApCiAgICAgICkKICAgICkKCiAgcF9oZWF0X2FtY2UgPC0gZ2dwbG90KAogICAgaGVhdG1hcF9kZiwKICAgIGFlcygKICAgICAgeCA9IHBhcnR5X24sCiAgICAgIHkgPSBsYWJlbF9oZWF0LAogICAgICBmaWxsID0gYWJzX2FtY2UKICAgICkKICApICsKICAgIGdlb21fdGlsZSgKICAgICAgY29sb3IgPSAiZ3JleTQ1IiwKICAgICAgbGluZXdpZHRoID0gMC4zCiAgICApICsKICAgIGdlb21fdGV4dCgKICAgICAgYWVzKAogICAgICAgIGxhYmVsID0gc3ByaW50ZigKICAgICAgICAgICIlLjFmIiwKICAgICAgICAgIGVzdGltYXRlX3BwCiAgICAgICAgKSwKICAgICAgICBjb2xvciA9IGlmX2Vsc2UoCiAgICAgICAgICByYW5rX3Njb3JlID49IDAuNTUsCiAgICAgICAgICAid2hpdGUiLAogICAgICAgICAgImJsYWNrIgogICAgICAgICkKICAgICAgKSwKICAgICAgc2l6ZSA9IDMuMQogICAgKSArCiAgICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICAgIGZhY2V0X2dyaWQoCiAgICAgIGF0dHJpYnV0ZSB+IC4sCiAgICAgIHNjYWxlcyA9ICJmcmVlX3kiLAogICAgICBzcGFjZSA9ICJmcmVlX3kiLAogICAgICBzd2l0Y2ggPSAieSIKICAgICkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudCgKICAgICAgbG93ID0gIndoaXRlIiwKICAgICAgaGlnaCA9ICJncmV5MjAiLAogICAgICBuYW1lID0gInxBTUNFfFxuKHBwKSIKICAgICkgKwogICAgbGFicygKICAgICAgc3VidGl0bGUgPSAi44K744Or5YaF44Gu5pWw5YCk44Gv56ym5Y+35LuY44GNQU1DRe+8iHBlcmNlbnRhZ2UgcG9pbnRz77yJIiwKICAgICAgeCA9ICLpgbjmip7ogqLmlbAiLAogICAgICB5ID0gTlVMTAogICAgKSArCiAgICB0aGVtZV9idygKICAgICAgYmFzZV9zaXplID0gMTIsCiAgICAgIGJhc2VfZmFtaWx5ID0gZmlndXJlX2ZvbnRfZmFtaWx5CiAgICApICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGZhY2UgPSAiYm9sZCIKICAgICAgKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KAogICAgICAgIGZpbGwgPSAiZ3JleTkyIiwKICAgICAgICBjb2xvciA9ICJncmV5NTUiCiAgICAgICksCiAgICAgIHN0cmlwLnRleHQueS5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGFuZ2xlID0gMCwKICAgICAgICBmYWNlID0gImJvbGQiCiAgICAgICksCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSA4LjUKICAgICAgKQogICAgKQoKICBwcmludChwX2hlYXRfYW1jZSkKCiAgc2F2ZV9wbG90KAogICAgImFtY2VfY292X2hlYXRtYXAucG5nIiwKICAgIHBfaGVhdF9hbWNlLAogICAgd2lkdGggPSAxMC41LAogICAgaGVpZ2h0ID0gMTEuNQogICkKCgogIGNvbmpvaW50X2Nsb2dpdCA8LSBjb25qb2ludF9hbGxfbSAlPiUKICAgIG11dGF0ZSgKICAgICAgc2VsZWN0ZWQgPSBhcy5pbnRlZ2VyKHNlbGVjdGVkKSwKICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoSUQpLAogICAgICB0YXNrX2lkID0gZmFjdG9yKHRhc2tfaWQpLAoKICAgICAgcGFydHlfbmFtZSA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBwYXJ0eV9uYW1lLAogICAgICAgIHBhcnR5X3JlZmVyZW5jZQogICAgICApLAoKICAgICAgZ2RwX2dyb3d0aCA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBnZHBfZ3Jvd3RoLAogICAgICAgIGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzJGdkcF9ncm93dGhbMV0KICAgICAgKSwKCiAgICAgIG5pa2tlaSA9IHJlbGV2ZWxfaWZfcHJlc2VudCgKICAgICAgICBuaWtrZWksCiAgICAgICAgYWxsb3dlZF9lY29ub21pY19sZXZlbHMkbmlra2VpWzFdCiAgICAgICksCgogICAgICBjcGkgPSByZWxldmVsX2lmX3ByZXNlbnQoCiAgICAgICAgY3BpLAogICAgICAgIGFsbG93ZWRfZWNvbm9taWNfbGV2ZWxzJGNwaVsxXQogICAgICApLAoKICAgICAgdW5lbXBsb3ltZW50ID0gcmVsZXZlbF9pZl9wcmVzZW50KAogICAgICAgIHVuZW1wbG95bWVudCwKICAgICAgICBhbGxvd2VkX2Vjb25vbWljX2xldmVscyR1bmVtcGxveW1lbnRbMV0KICAgICAgKQogICAgKQoKICBmb3JtdWxhX2Nsb2dpdF9ub2NvdiA8LSBhcy5mb3JtdWxhKAogICAgcGFzdGUwKAogICAgICAic2VsZWN0ZWQgfiAiLAogICAgICBwYXN0ZSgKICAgICAgICBhdHRyX3Rlcm1zLAogICAgICAgIGNvbGxhcHNlID0gIiArICIKICAgICAgKSwKICAgICAgIiArIHN0cmF0YSh0YXNrX2lkKSArIGNsdXN0ZXIoSUQpIgogICAgKQogICkKCiAgcnVuX2Nsb2dpdF9ub2NvdiA8LSBmdW5jdGlvbihkYXQpIHsKICAgIHN1cnZpdmFsOjpjbG9naXQoCiAgICAgIGZvcm11bGFfY2xvZ2l0X25vY292LAogICAgICBkYXRhID0gZGF0LAogICAgICBtZXRob2QgPSAiZWZyb24iCiAgICApCiAgfQoKICBtb2RlbHNfY2xvZ2l0X25vY292IDwtIGNvbmpvaW50X2Nsb2dpdCAlPiUKICAgIHNwbGl0KC4kcGFydHlfbikgJT4lCiAgICBtYXAocnVuX2Nsb2dpdF9ub2NvdikKCiAgY2FwdHVyZS5vdXRwdXQoCiAgICBsYXBwbHkoCiAgICAgIG1vZGVsc19jbG9naXRfbm9jb3YsCiAgICAgIHN1bW1hcnkKICAgICksCiAgICBmaWxlID0gZmlsZS5wYXRoKAogICAgICBvdXRwdXRfZGlyLAogICAgICAiY29uZGl0aW9uYWxfbG9naXRfbW9kZWxzLnR4dCIKICAgICkKICApCgogIHRpZHlfY2xvZ2l0IDwtIGZ1bmN0aW9uKG1vZGVsKSB7CiAgICBzIDwtIHN1bW1hcnkobW9kZWwpCiAgICBjdCA8LSBhcy5kYXRhLmZyYW1lKAogICAgICBzJGNvZWZmaWNpZW50cwogICAgKQogICAgY3QkdGVybSA8LSByb3duYW1lcyhjdCkKCiAgICBzZV9jb2wgPC0gaWYgKAogICAgICAicm9idXN0IHNlIiAlaW4lIG5hbWVzKGN0KQogICAgKSB7CiAgICAgICJyb2J1c3Qgc2UiCiAgICB9IGVsc2UgaWYgKAogICAgICAic2UoY29lZikiICVpbiUgbmFtZXMoY3QpCiAgICApIHsKICAgICAgInNlKGNvZWYpIgogICAgfSBlbHNlIHsKICAgICAgc3RvcCgiQ2hlY2sgY2xvZ2l0IikKICAgIH0KCiAgICBwX2NvbCA8LSBpZiAoCiAgICAgICJQcig+fHp8KSIgJWluJSBuYW1lcyhjdCkKICAgICkgewogICAgICAiUHIoPnx6fCkiCiAgICB9IGVsc2UgaWYgKAogICAgICAiUHIoPnx0fCkiICVpbiUgbmFtZXMoY3QpCiAgICApIHsKICAgICAgIlByKD58dHwpIgogICAgfSBlbHNlIHsKICAgICAgTkFfY2hhcmFjdGVyXwogICAgfQoKICAgIGN0ICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgdHJhbnNtdXRlKAogICAgICAgIHRlcm0gPSB0ZXJtLAogICAgICAgIGVzdGltYXRlID0gY29lZiwKICAgICAgICBzdGQuZXJyb3IgPSAuZGF0YVtbc2VfY29sXV0sCgogICAgICAgIHAudmFsdWUgPSBpZiAoCiAgICAgICAgICAhaXMubmEocF9jb2wpCiAgICAgICAgKSB7CiAgICAgICAgICAuZGF0YVtbcF9jb2xdXQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBOQV9yZWFsXwogICAgICAgIH0sCgogICAgICAgIGNvbmYubG93ID0KICAgICAgICAgIGVzdGltYXRlIC0KICAgICAgICAgIDEuOTYgKgogICAgICAgICAgc3RkLmVycm9yLAoKICAgICAgICBjb25mLmhpZ2ggPQogICAgICAgICAgZXN0aW1hdGUgKwogICAgICAgICAgMS45NiAqCiAgICAgICAgICBzdGQuZXJyb3IsCgogICAgICAgIG9kZHNfcmF0aW8gPSBleHAoCiAgICAgICAgICBlc3RpbWF0ZQogICAgICAgICksCgogICAgICAgIG9kZHNfcmF0aW9fbG93ID0gZXhwKAogICAgICAgICAgY29uZi5sb3cKICAgICAgICApLAoKICAgICAgICBvZGRzX3JhdGlvX2hpZ2ggPSBleHAoCiAgICAgICAgICBjb25mLmhpZ2gKICAgICAgICApCiAgICAgICkKICB9CgogIGNsb2dpdF9wbG90X2RmIDwtIGltYXBfZGZyKAogICAgbW9kZWxzX2Nsb2dpdF9ub2NvdiwKICAgIH4gdGlkeV9jbG9naXQoLngpICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgcGFydHlfbiA9IGFzLmNoYXJhY3RlcigueSkKICAgICAgKQogICkgJT4lCiAgICBsZWZ0X2pvaW4oCiAgICAgIHRlcm1fbGFiZWxzLAogICAgICBieSA9ICJ0ZXJtIgogICAgKSAlPiUKICAgIGZpbHRlcigKICAgICAgIWlzLm5hKGF0dHJpYnV0ZSkKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIHBhcnR5X24gPSBmYWN0b3IoCiAgICAgICAgcGFydHlfbiwKICAgICAgICBsZXZlbHMgPSBjKAogICAgICAgICAgIjIiLAogICAgICAgICAgIjMiLAogICAgICAgICAgIjQiLAogICAgICAgICAgIjUiCiAgICAgICAgKSwKICAgICAgICBsYWJlbHMgPSBjKAogICAgICAgICAgIjLpgbjmip7ogqIiLAogICAgICAgICAgIjPpgbjmip7ogqIiLAogICAgICAgICAgIjTpgbjmip7ogqIiLAogICAgICAgICAgIjXpgbjmip7ogqIiCiAgICAgICAgKQogICAgICApLAoKICAgICAgYXR0cmlidXRlID0gZmFjdG9yKAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbHMgPSBhdHRyaWJ1dGVfb3JkZXIKICAgICAgKSwKCiAgICAgIGxhYmVsID0gZmFjdG9yKAogICAgICAgIGxhYmVsLAogICAgICAgIGxldmVscyA9IHJldigKICAgICAgICAgIGxhYmVsX29yZGVyCiAgICAgICAgKQogICAgICApCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBjbG9naXRfcGxvdF9kZiwKICAgICJjb25kaXRpb25hbF9sb2dpdF9jb2VmZmljaWVudHMuY3N2IgogICkKCgogIHBfY2xvZ2l0X29yIDwtIGdncGxvdCgKICAgIGNsb2dpdF9wbG90X2RmLAogICAgYWVzKAogICAgICB4ID0gb2Rkc19yYXRpbywKICAgICAgeSA9IGxhYmVsLAogICAgICBzaGFwZSA9IHBhcnR5X24sCiAgICAgIGxpbmV0eXBlID0gcGFydHlfbiwKICAgICAgZ3JvdXAgPSBwYXJ0eV9uCiAgICApCiAgKSArCiAgICBnZW9tX3ZsaW5lKAogICAgICB4aW50ZXJjZXB0ID0gMSwKICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgbGluZXdpZHRoID0gMC40NSwKICAgICAgY29sb3IgPSAiZ3JleTM1IgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyaCgKICAgICAgYWVzKAogICAgICAgIHhtaW4gPSBvZGRzX3JhdGlvX2xvdywKICAgICAgICB4bWF4ID0gb2Rkc19yYXRpb19oaWdoCiAgICAgICksCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoCiAgICAgICAgd2lkdGggPSAwLjcyCiAgICAgICksCiAgICAgIGhlaWdodCA9IDAuMTUsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX3BvaW50KAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKAogICAgICAgIHdpZHRoID0gMC43MgogICAgICApLAogICAgICBzaXplID0gMi40LAogICAgICBzdHJva2UgPSAwLjcsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV94X2xvZzEwKAogICAgICBicmVha3MgPSBzY2FsZXM6OmxvZ19icmVha3MoCiAgICAgICAgbiA9IDgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoCiAgICAgICAgIjLpgbjmip7ogqIiID0gMTYsCiAgICAgICAgIjPpgbjmip7ogqIiID0gMTcsCiAgICAgICAgIjTpgbjmip7ogqIiID0gMTUsCiAgICAgICAgIjXpgbjmip7ogqIiID0gMQogICAgICApCiAgICApICsKICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygKICAgICAgICAiMumBuOaKnuiCoiIgPSAic29saWQiLAogICAgICAgICIz6YG45oqe6IKiIiA9ICJkYXNoZWQiLAogICAgICAgICI06YG45oqe6IKiIiA9ICJkb3RkYXNoIiwKICAgICAgICAiNemBuOaKnuiCoiIgPSAidHdvZGFzaCIKICAgICAgKQogICAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBhdHRyaWJ1dGUgfiAuLAogICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgc3BhY2UgPSAiZnJlZV95IiwKICAgICAgc3dpdGNoID0gInkiCiAgICApICsKICAgIGxhYnMoCiAgICAgIHggPSAi44Kq44OD44K65q+UIiwKICAgICAgeSA9IE5VTEwsCiAgICAgIHNoYXBlID0gIumBuOaKnuiCouaVsCIsCiAgICAgIGxpbmV0eXBlID0gIumBuOaKnuiCouaVsCIKICAgICkgKwogICAgdGhlbWVfYncoCiAgICAgIGJhc2Vfc2l6ZSA9IDEyLAogICAgICBiYXNlX2ZhbWlseSA9IGZpZ3VyZV9mb250X2ZhbWlseQogICAgKSArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiCiAgICAgICksCiAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICBmaWxsID0gImdyZXk5MiIsCiAgICAgICAgY29sb3IgPSAiZ3JleTU1IgogICAgICApLAogICAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBhbmdsZSA9IDAsCiAgICAgICAgZmFjZSA9ICJib2xkIgogICAgICApLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBzaXplID0gOC41CiAgICAgICkKICAgICkKCiAgcHJpbnQocF9jbG9naXRfb3IpCgogIHNhdmVfcGxvdCgKICAgICJjbG9naXRfb2Rkc3JhdGlvX25vY292LnBuZyIsCiAgICBwX2Nsb2dpdF9vciwKICAgIHdpZHRoID0gMTAuNSwKICAgIGhlaWdodCA9IDExLjUKICApCgoKICBleHBlcmltZW50YWxfcGFydHlfbmFtZXMgPC0gYXMuY2hhcmFjdGVyKAogICAgcGFydHlfbGV2ZWxzX3VzZQogICkKCiAgY29uam9pbnRfbWF0Y2ggPC0gY29uam9pbnRfYWxsX2NvdiAlPiUKICAgIG11dGF0ZSgKICAgICAgcGFydHlfbmFtZV9jaHIgPSBhcy5jaGFyYWN0ZXIocGFydHlfbmFtZSksCiAgICAgIAogICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkID0gaWZfZWxzZSgKICAgICAgICBwYXJ0eV9zdXBwb3J0X3Byb2ZpbGUgJWluJSBleHBlcmltZW50YWxfcGFydHlfbmFtZXMsCiAgICAgICAgcGFydHlfc3VwcG9ydF9wcm9maWxlLAogICAgICAgIE5BX2NoYXJhY3Rlcl8KICAgICAgKSwKICAgICAgCiAgICAgIHBhcnR5X21hdGNoID0gY2FzZV93aGVuKAogICAgICAgIGlzLm5hKHN1cHBvcnRfcGFydHlfdmFsaWQpIH4gTkFfaW50ZWdlcl8sCiAgICAgICAgcGFydHlfbmFtZV9jaHIgPT0gc3VwcG9ydF9wYXJ0eV92YWxpZCB+IDFMLAogICAgICAgIFRSVUUgfiAwTAogICAgICApCiAgICApICU+JQogICAgZmlsdGVyKAogICAgICAhaXMubmEocGFydHlfbWF0Y2gpCiAgICApCgogIHBhcnR5X21hdGNoX3NhbXBsZSA8LSBjb25qb2ludF9tYXRjaCAlPiUKICAgIGRpc3RpbmN0KAogICAgICBJRCwKICAgICAgcGFydHlfbiwKICAgICAgc3VwcG9ydF9wYXJ0eV92YWxpZAogICAgKSAlPiUKICAgIGNvdW50KAogICAgICBwYXJ0eV9uLAogICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkLAogICAgICBuYW1lID0gIm5fcmVzcG9uZGVudHMiCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBwYXJ0eV9tYXRjaF9zYW1wbGUsCiAgICAicGFydHlfbWF0Y2hfc2FtcGxlLmNzdiIKICApCgoKICBmb3JtdWxhX3BhcnR5X21hdGNoX292ZXJhbGwgPC0gYXMuZm9ybXVsYSgKICAgIHBhc3RlKAogICAgICAic2VsZWN0ZWQgfiIsCiAgICAgIHBhc3RlKAogICAgICAgIGMoCiAgICAgICAgICAicGFydHlfbmFtZSIsCiAgICAgICAgICAicGFydHlfbWF0Y2giLAogICAgICAgICAgZWNvbm9taWNfYXR0cl90ZXJtcwogICAgICAgICksCiAgICAgICAgY29sbGFwc2UgPSAiICsgIgogICAgICApCiAgICApCiAgKQoKICBydW5fcGFydHlfbWF0Y2hfb3ZlcmFsbCA8LSBmdW5jdGlvbihkYXQpIHsKICAgIGZlb2xzKAogICAgICBmb3JtdWxhX3BhcnR5X21hdGNoX292ZXJhbGwsCiAgICAgIGRhdGEgPSBkYXQsCiAgICAgIHZjb3YgPSB+IElECiAgICApCiAgfQoKICBtb2RlbHNfcGFydHlfbWF0Y2hfYnlfbiA8LSBjb25qb2ludF9tYXRjaCAlPiUKICAgIHNwbGl0KC4kcGFydHlfbikgJT4lCiAgICBtYXAocnVuX3BhcnR5X21hdGNoX292ZXJhbGwpCgogIG1fcGFydHlfbWF0Y2hfaW50ZXJhY3Rpb24gPC0gZmVvbHMoCiAgICBzZWxlY3RlZCB+CiAgICAgIHBhcnR5X25fZiAqCiAgICAgIHBhcnR5X21hdGNoICsKICAgICAgcGFydHlfbmFtZSArCiAgICAgIGdkcF9ncm93dGggKwogICAgICBuaWtrZWkgKwogICAgICBjcGkgKwogICAgICB1bmVtcGxveW1lbnQsCiAgICBkYXRhID0gY29uam9pbnRfbWF0Y2gsCiAgICB2Y292ID0gfiBJRAogICkKCiAgY2FwdHVyZS5vdXRwdXQoCiAgICBsYXBwbHkoCiAgICAgIG1vZGVsc19wYXJ0eV9tYXRjaF9ieV9uLAogICAgICBzdW1tYXJ5CiAgICApLAogICAgZmlsZSA9IGZpbGUucGF0aCgKICAgICAgb3V0cHV0X2RpciwKICAgICAgInBhcnR5X21hdGNoX21vZGVsc19ieV9jaG9pY2VfbnVtYmVyLnR4dCIKICAgICkKICApCgogIGNhcHR1cmUub3V0cHV0KAogICAgc3VtbWFyeShtX3BhcnR5X21hdGNoX2ludGVyYWN0aW9uKSwKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJwYXJ0eV9tYXRjaF9pbnRlcmFjdGlvbl9tb2RlbC50eHQiCiAgICApCiAgKQoKICBleHRyYWN0X3BhcnR5X21hdGNoX3Rlcm0gPC0gZnVuY3Rpb24obW9kZWwpIHsKICAgIG91dCA8LSB0aWR5X2ZpeGVzdChtb2RlbCkgJT4lCiAgICAgIGZpbHRlcih0ZXJtID09ICJwYXJ0eV9tYXRjaCIpCiAgICAKICAgIGlmIChucm93KG91dCkgPT0gMCkgewogICAgICByZXR1cm4oCiAgICAgICAgdGliYmxlKAogICAgICAgICAgdGVybSA9ICJwYXJ0eV9tYXRjaCIsCiAgICAgICAgICBlc3RpbWF0ZSA9IE5BX3JlYWxfLAogICAgICAgICAgc3RkLmVycm9yID0gTkFfcmVhbF8sCiAgICAgICAgICBzdGF0aXN0aWMgPSBOQV9yZWFsXywKICAgICAgICAgIHAudmFsdWUgPSBOQV9yZWFsXywKICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICBjb25mLmhpZ2ggPSBOQV9yZWFsXwogICAgICAgICkKICAgICAgKQogICAgfQogICAgCiAgICBvdXQKICB9CgogIHBhcnR5X21hdGNoX2NvZWZfZGYgPC0gaW1hcF9kZnIoCiAgICBtb2RlbHNfcGFydHlfbWF0Y2hfYnlfbiwKICAgIH4gZXh0cmFjdF9wYXJ0eV9tYXRjaF90ZXJtKC54KSAlPiUKICAgICAgbXV0YXRlKAogICAgICAgIHN1cHBvcnRfZ3JvdXAgPSAi5YWo5L2TIiwKICAgICAgICBzdXBwb3J0X2dyb3VwX2xhYmVsID0gIuWFqOS9kyIsCiAgICAgICAgcGFydHlfbiA9IGFzLmludGVnZXIoLnkpCiAgICAgICkKICApICU+JQogICAgbXV0YXRlKAogICAgICBlc3RpbWF0ZV9wcCA9IGVzdGltYXRlICogMTAwLAogICAgICBjb25mLmxvd19wcCA9IGNvbmYubG93ICogMTAwLAogICAgICBjb25mLmhpZ2hfcHAgPSBjb25mLmhpZ2ggKiAxMDAsCiAgICAgIAogICAgICBwYXJ0eV9uX2xhYmVsID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gMjo1LAogICAgICAgIGxhYmVscyA9IGMoCiAgICAgICAgICAiMumBuOaKnuiCoiIsCiAgICAgICAgICAiM+mBuOaKnuiCoiIsCiAgICAgICAgICAiNOmBuOaKnuiCoiIsCiAgICAgICAgICAiNemBuOaKnuiCoiIKICAgICAgICApCiAgICAgICkKICAgICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHBhcnR5X21hdGNoX2NvZWZfZGYsCiAgICAicGFydHlfbWF0Y2hfY29lZmZpY2llbnRzLmNzdiIKICApCgoKICB0YXJnZXRfc3VwcG9ydF9ncm91cHMgPC0gYygKICAgICLoh6rnlLHmsJHkuLvlhZoiLAogICAgIuS4remBk+aUuemdqemAo+WQiCIsCiAgICAi56uL5oay5rCR5Li75YWaIiwKICAgICLlj4LmlL/lhZoiCiAgKQoKICB0YXJnZXRfc3VwcG9ydF9sYWJlbHMgPC0gYygKICAgICLoh6rnlLHmsJHkuLvlhZoiICAgPSAi6Ieq5rCR5YWa5pSv5oyB6ICFIiwKICAgICLkuK3pgZPmlLnpnanpgKPlkIgiID0gIuS4remBk+aUuemdqeaUr+aMgeiAhSIsCiAgICAi56uL5oay5rCR5Li75YWaIiAgID0gIueri+aGsuaUr+aMgeiAhSIsCiAgICAi5Y+C5pS/5YWaIiAgICAgICA9ICLlj4LmlL/lhZrmlK/mjIHogIUiCiAgKQoKICBwYXJ0eV9tYXRjaF9zdWJncm91cF9zYW1wbGUgPC0gY29uam9pbnRfbWF0Y2ggJT4lCiAgICBkaXN0aW5jdCgKICAgICAgSUQsCiAgICAgIHBhcnR5X24sCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQKICAgICkgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgJWluJSB0YXJnZXRfc3VwcG9ydF9ncm91cHMKICAgICkgJT4lCiAgICBjb3VudCgKICAgICAgc3VwcG9ydF9wYXJ0eV92YWxpZCwKICAgICAgcGFydHlfbiwKICAgICAgbmFtZSA9ICJuX3Jlc3BvbmRlbnRzIgogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgc3VwcG9ydF9ncm91cF9sYWJlbCA9IHJlY29kZSgKICAgICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkLAogICAgICAgICEhIXRhcmdldF9zdXBwb3J0X2xhYmVscwogICAgICApCiAgICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICBwYXJ0eV9tYXRjaF9zdWJncm91cF9zYW1wbGUsCiAgICAicGFydHlfbWF0Y2hfc3ViZ3JvdXBfc2FtcGxlLmNzdiIKICApCgogIHN1cHBvcnRfZ3JvdXBfdG90YWxfbiA8LSBjb25qb2ludF9tYXRjaCAlPiUKICAgIGRpc3RpbmN0KAogICAgICBJRCwKICAgICAgc3VwcG9ydF9wYXJ0eV92YWxpZAogICAgKSAlPiUKICAgIGZpbHRlcigKICAgICAgc3VwcG9ydF9wYXJ0eV92YWxpZCAlaW4lIHRhcmdldF9zdXBwb3J0X2dyb3VwcwogICAgKSAlPiUKICAgIGNvdW50KAogICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkLAogICAgICBuYW1lID0gIm5fdG90YWwiCiAgICApCgogIGZvcm11bGFfcGFydHlfbWF0Y2hfc3ViZ3JvdXAgPC0gYXMuZm9ybXVsYSgKICAgIHBhc3RlKAogICAgICAic2VsZWN0ZWQgfiIsCiAgICAgIHBhc3RlKAogICAgICAgIGMoCiAgICAgICAgICAicGFydHlfbWF0Y2giLAogICAgICAgICAgZWNvbm9taWNfYXR0cl90ZXJtcwogICAgICAgICksCiAgICAgICAgY29sbGFwc2UgPSAiICsgIgogICAgICApCiAgICApCiAgKQoKICBydW5fcGFydHlfbWF0Y2hfc3ViZ3JvdXAgPC0gZnVuY3Rpb24oZGF0KSB7CiAgICBmZW9scygKICAgICAgZm9ybXVsYV9wYXJ0eV9tYXRjaF9zdWJncm91cCwKICAgICAgZGF0YSA9IGRhdCwKICAgICAgdmNvdiA9IH4gSUQKICAgICkKICB9CgogIGVzdGltYXRlX3BhcnR5X21hdGNoX3N1Ymdyb3VwIDwtIGZ1bmN0aW9uKAogICAgICBkYXQsCiAgICAgIHN1cHBvcnRfZ3JvdXBfdmFsdWUKICApIHsKICAgIG1hcF9kZnIoCiAgICAgIDI6NSwKICAgICAgZnVuY3Rpb24obl92YWx1ZSkgewogICAgICAgIAogICAgICAgIGRhdF9uIDwtIGRhdCAlPiUKICAgICAgICAgIGZpbHRlcigKICAgICAgICAgICAgcGFydHlfbiA9PSBuX3ZhbHVlLAogICAgICAgICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkID09IHN1cHBvcnRfZ3JvdXBfdmFsdWUKICAgICAgICAgICkKICAgICAgICAKICAgICAgICBuX2lkcyA8LSBuX2Rpc3RpbmN0KGRhdF9uJElEKQogICAgICAgIAogICAgICAgIGlmIChucm93KGRhdF9uKSA9PSAwIHx8IG5faWRzID09IDApIHsKICAgICAgICAgIHJldHVybigKICAgICAgICAgICAgdGliYmxlKAogICAgICAgICAgICAgIHRlcm0gPSAicGFydHlfbWF0Y2giLAogICAgICAgICAgICAgIGVzdGltYXRlID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3RkLmVycm9yID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3RhdGlzdGljID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgcC52YWx1ZSA9IE5BX3JlYWxfLAogICAgICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgY29uZi5oaWdoID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3VwcG9ydF9ncm91cCA9IHN1cHBvcnRfZ3JvdXBfdmFsdWUsCiAgICAgICAgICAgICAgc3VwcG9ydF9ncm91cF9sYWJlbCA9IHVubmFtZSgKICAgICAgICAgICAgICAgIHRhcmdldF9zdXBwb3J0X2xhYmVsc1tbc3VwcG9ydF9ncm91cF92YWx1ZV1dCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBwYXJ0eV9uID0gbl92YWx1ZSwKICAgICAgICAgICAgICBuX2lkcyA9IG5faWRzCiAgICAgICAgICAgICkKICAgICAgICAgICkKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgbW9kZWxfbiA8LSB0cnlDYXRjaCgKICAgICAgICAgIHJ1bl9wYXJ0eV9tYXRjaF9zdWJncm91cChkYXRfbiksCiAgICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwKICAgICAgICApCiAgICAgICAgCiAgICAgICAgaWYgKGlzLm51bGwobW9kZWxfbikpIHsKICAgICAgICAgIHJldHVybigKICAgICAgICAgICAgdGliYmxlKAogICAgICAgICAgICAgIHRlcm0gPSAicGFydHlfbWF0Y2giLAogICAgICAgICAgICAgIGVzdGltYXRlID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3RkLmVycm9yID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3RhdGlzdGljID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgcC52YWx1ZSA9IE5BX3JlYWxfLAogICAgICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgY29uZi5oaWdoID0gTkFfcmVhbF8sCiAgICAgICAgICAgICAgc3VwcG9ydF9ncm91cCA9IHN1cHBvcnRfZ3JvdXBfdmFsdWUsCiAgICAgICAgICAgICAgc3VwcG9ydF9ncm91cF9sYWJlbCA9IHVubmFtZSgKICAgICAgICAgICAgICAgIHRhcmdldF9zdXBwb3J0X2xhYmVsc1tbc3VwcG9ydF9ncm91cF92YWx1ZV1dCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBwYXJ0eV9uID0gbl92YWx1ZSwKICAgICAgICAgICAgICBuX2lkcyA9IG5faWRzCiAgICAgICAgICAgICkKICAgICAgICAgICkKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgZXh0cmFjdF9wYXJ0eV9tYXRjaF90ZXJtKG1vZGVsX24pICU+JQogICAgICAgICAgbXV0YXRlKAogICAgICAgICAgICBzdXBwb3J0X2dyb3VwID0gc3VwcG9ydF9ncm91cF92YWx1ZSwKICAgICAgICAgICAgc3VwcG9ydF9ncm91cF9sYWJlbCA9IHVubmFtZSgKICAgICAgICAgICAgICB0YXJnZXRfc3VwcG9ydF9sYWJlbHNbW3N1cHBvcnRfZ3JvdXBfdmFsdWVdXQogICAgICAgICAgICApLAogICAgICAgICAgICBwYXJ0eV9uID0gbl92YWx1ZSwKICAgICAgICAgICAgbl9pZHMgPSBuX2lkcwogICAgICAgICAgKQogICAgICB9CiAgICApCiAgfQoKICBwYXJ0eV9tYXRjaF9zdWJncm91cF9jb2VmX2RmIDwtIG1hcF9kZnIoCiAgICB0YXJnZXRfc3VwcG9ydF9ncm91cHMsCiAgICB+IGVzdGltYXRlX3BhcnR5X21hdGNoX3N1Ymdyb3VwKAogICAgICBjb25qb2ludF9tYXRjaCwKICAgICAgLngKICAgICkKICApICU+JQogICAgbGVmdF9qb2luKAogICAgICBzdXBwb3J0X2dyb3VwX3RvdGFsX24sCiAgICAgIGJ5ID0gYygKICAgICAgICAic3VwcG9ydF9ncm91cCIgPSAic3VwcG9ydF9wYXJ0eV92YWxpZCIKICAgICAgKQogICAgKSAlPiUKICAgIG11dGF0ZSgKICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICBwYXJ0eV9uX2xhYmVsID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gMjo1LAogICAgICAgIGxhYmVscyA9IGMoCiAgICAgICAgICAiMumBuOaKnuiCoiIsCiAgICAgICAgICAiM+mBuOaKnuiCoiIsCiAgICAgICAgICAiNOmBuOaKnuiCoiIsCiAgICAgICAgICAiNemBuOaKnuiCoiIKICAgICAgICApCiAgICAgICkKICAgICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHBhcnR5X21hdGNoX3N1Ymdyb3VwX2NvZWZfZGYsCiAgICAicGFydHlfbWF0Y2hfc3ViZ3JvdXBfY29lZmZpY2llbnRzLmNzdiIKICApCgoKICBwYXJ0eV9tYXRjaF9wbG90X2RmX2FsbCA8LSBiaW5kX3Jvd3MoCiAgICBwYXJ0eV9tYXRjaF9jb2VmX2RmICU+JQogICAgICBtdXRhdGUocGFuZWwgPSAib3ZlcmFsbCIpLAogICAgcGFydHlfbWF0Y2hfc3ViZ3JvdXBfY29lZl9kZiAlPiUKICAgICAgbXV0YXRlKHBhbmVsID0gInN1Ymdyb3VwIikKICApICU+JQogICAgZmlsdGVyKAogICAgICBpcy5maW5pdGUoZXN0aW1hdGVfcHApLAogICAgICBpcy5maW5pdGUoY29uZi5sb3dfcHApLAogICAgICBpcy5maW5pdGUoY29uZi5oaWdoX3BwKQogICAgKQoKICBpZiAobnJvdyhwYXJ0eV9tYXRjaF9wbG90X2RmX2FsbCkgPT0gMCkgewogICAgc3RvcCgiQ2hlY2sgZGF0YSIpCiAgfQoKICB5X3JhbmdlX21hdGNoIDwtIHJhbmdlKAogICAgYygKICAgICAgcGFydHlfbWF0Y2hfcGxvdF9kZl9hbGwkY29uZi5sb3dfcHAsCiAgICAgIHBhcnR5X21hdGNoX3Bsb3RfZGZfYWxsJGNvbmYuaGlnaF9wcAogICAgKSwKICAgIG5hLnJtID0gVFJVRQogICkKCiAgeV9zcGFuX21hdGNoIDwtIGRpZmYoeV9yYW5nZV9tYXRjaCkKCiAgaWYgKCFpcy5maW5pdGUoeV9zcGFuX21hdGNoKSB8fCB5X3NwYW5fbWF0Y2ggPD0gMCkgewogICAgeV9zcGFuX21hdGNoIDwtIDUKICB9CgogIHlfcGFkX21hdGNoIDwtIG1heCgxLjIsIDAuMTAgKiB5X3NwYW5fbWF0Y2gpCgogIHlfbGltaXRzX21hdGNoIDwtIGMoCiAgICB5X3JhbmdlX21hdGNoWzFdIC0geV9wYWRfbWF0Y2gsCiAgICB5X3JhbmdlX21hdGNoWzJdICsgeV9wYWRfbWF0Y2gKICApCgoKICB0aGVtZV9wYXJ0eV9tYXRjaF9idyA8LSB0aGVtZV9idygKICAgIGJhc2Vfc2l6ZSA9IDEyLAogICAgYmFzZV9mYW1pbHkgPSBmaWd1cmVfZm9udF9mYW1pbHkKICApICsKICAgIHRoZW1lKAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKAogICAgICAgIGxpbmV3aWR0aCA9IDAuMzAsCiAgICAgICAgY29sb3IgPSAiZ3JleTg4IgogICAgICApLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgbGluZXdpZHRoID0gMC42NSwKICAgICAgICBjb2xvciA9ICJibGFjayIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICBmYWNlID0gImJvbGQiCiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IHJlbCgwLjkyKQogICAgICApLAogICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigKICAgICAgICA4LCAxMCwgOCwgOAogICAgICApCiAgICApCgoKICBtYWtlX3BhcnR5X21hdGNoX3BhbmVsX3Bsb3QgPC0gZnVuY3Rpb24oCiAgICAgIGRhdCwKICAgICAgcGFuZWxfdGl0bGUsCiAgICAgIHBhbmVsX3N1YnRpdGxlID0gTlVMTCwKICAgICAgYmFzZV9zaXplID0gMTEsCiAgICAgIHNob3dfeV90aXRsZSA9IFRSVUUsCiAgICAgIHNob3dfeF90aXRsZSA9IFRSVUUKICApIHsKICAgIGdncGxvdCgKICAgICAgZGF0LAogICAgICBhZXMoCiAgICAgICAgeCA9IHBhcnR5X24sCiAgICAgICAgeSA9IGVzdGltYXRlX3BwCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX2xpbmUoCiAgICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICkgKwogICAgICBnZW9tX2Vycm9yYmFyKAogICAgICAgIGFlcygKICAgICAgICAgIHltaW4gPSBjb25mLmxvd19wcCwKICAgICAgICAgIHltYXggPSBjb25mLmhpZ2hfcHAKICAgICAgICApLAogICAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICkgKwogICAgICBnZW9tX2xhYmVsKAogICAgICAgIGFlcygKICAgICAgICAgIGxhYmVsID0gc3ByaW50ZigiJS4xZiBwcCIsIGVzdGltYXRlX3BwKQogICAgICAgICksCiAgICAgICAgc2l6ZSA9IDMuNDUsCiAgICAgICAgZmFtaWx5ID0gZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICAgIGxhYmVsLnNpemUgPSAwLAogICAgICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KAogICAgICAgICAgMC4xMiwKICAgICAgICAgICJsaW5lcyIKICAgICAgICApLAogICAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgKSArCiAgICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICBicmVha3MgPSAyOjUsCiAgICAgICAgbGFiZWxzID0gcGFzdGUwKAogICAgICAgICAgMjo1LAogICAgICAgICAgIumBuOaKnuiCoiIKICAgICAgICApLAogICAgICAgIGxpbWl0cyA9IGMoMS43MiwgNS4yOCkKICAgICAgKSArCiAgICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICBwYXN0ZTAoeCwgIiBwcCIpCiAgICAgICAgfSwKICAgICAgICBicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDYpLAogICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbigKICAgICAgICAgIG11bHQgPSBjKDAuMDUsIDAuMDgpCiAgICAgICAgKQogICAgICApICsKICAgICAgY29vcmRfY2FydGVzaWFuKAogICAgICAgIHlsaW0gPSB5X2xpbWl0c19tYXRjaAogICAgICApICsKICAgICAgbGFicygKICAgICAgICB0aXRsZSA9IHBhbmVsX3RpdGxlLAogICAgICAgIHN1YnRpdGxlID0gcGFuZWxfc3VidGl0bGUsCiAgICAgICAgeCA9IGlmIChzaG93X3hfdGl0bGUpICLpgbjmip7ogqLmlbAiIGVsc2UgTlVMTCwKICAgICAgICB5ID0gaWYgKHNob3dfeV90aXRsZSkgIuS4gOiHtOOBl+OBn+WgtOWQiOOBrumBuOaKnueiuueOh+OBruWkieWMliIgZWxzZSBOVUxMCiAgICAgICkgKwogICAgICB0aGVtZV9idygKICAgICAgICBiYXNlX3NpemUgPSBiYXNlX3NpemUsCiAgICAgICAgYmFzZV9mYW1pbHkgPSBmaWd1cmVfZm9udF9mYW1pbHkKICAgICAgKSArCiAgICAgIHRoZW1lX3BhcnR5X21hdGNoX2J3ICsKICAgICAgdGhlbWUoCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgKICAgICAgICAgIGZhY2UgPSAiYm9sZCIKICAgICAgICApLAogICAgICAgIGF4aXMudGl0bGUueCA9IGlmIChzaG93X3hfdGl0bGUpIGVsZW1lbnRfdGV4dCgpIGVsc2UgZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGlmIChzaG93X3lfdGl0bGUpIGVsZW1lbnRfdGV4dCgpIGVsc2UgZWxlbWVudF9ibGFuaygpCiAgICAgICkKICB9CgogIG1ha2Vfc3VwcG9ydF9ncm91cF90aXRsZSA8LSBmdW5jdGlvbigKICAgICAgc3VwcG9ydF9ncm91cF92YWx1ZQogICkgewogICAgbl92YWx1ZSA8LSBzdXBwb3J0X2dyb3VwX3RvdGFsX24gJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkID09IHN1cHBvcnRfZ3JvdXBfdmFsdWUKICAgICAgKSAlPiUKICAgICAgcHVsbChuX3RvdGFsKQogICAgCiAgICBpZiAobGVuZ3RoKG5fdmFsdWUpID09IDAgfHwgaXMubmEobl92YWx1ZSkpIHsKICAgICAgbl92YWx1ZSA8LSAwCiAgICB9CiAgICAKICAgIHBhc3RlMCgKICAgICAgdGFyZ2V0X3N1cHBvcnRfbGFiZWxzW1tzdXBwb3J0X2dyb3VwX3ZhbHVlXV0sCiAgICAgICJcbihuPSIsCiAgICAgIHNjYWxlczo6Y29tbWEobl92YWx1ZSksCiAgICAgICIpIgogICAgKQogIH0KCgogIHBfcGFydHlfbWF0Y2hfb3ZlcmFsbCA8LSBtYWtlX3BhcnR5X21hdGNoX3BhbmVsX3Bsb3QoCiAgICBwYXJ0eV9tYXRjaF9jb2VmX2RmLAogICAgcGFuZWxfdGl0bGUgPSBOVUxMLAogICAgcGFuZWxfc3VidGl0bGUgPQogICAgICAi5LiK5q6144Gv5YWo5L2T44CB5LiL5q6144Gv5pSv5oyB5pS/5YWa5Yil77yI6Ieq5rCR44O75Lit6YGT5pS56Z2p44O756uL5oay44O75Y+C5pS/77yJ44CC5pS/5YWa5ZCN44Go57WM5riI5bGe5oCn44KS57Wx5Yi244GX44Gf57ea5b2i56K6546H44Oi44OH44Or44CCIiwKICAgIGJhc2Vfc2l6ZSA9IDEyLAogICAgc2hvd195X3RpdGxlID0gVFJVRSwKICAgIHNob3dfeF90aXRsZSA9IFRSVUUKICApCgoKICBwX3BhcnR5X21hdGNoX2xkcCA8LSBtYWtlX3BhcnR5X21hdGNoX3BhbmVsX3Bsb3QoCiAgICBwYXJ0eV9tYXRjaF9zdWJncm91cF9jb2VmX2RmICU+JQogICAgICBmaWx0ZXIoc3VwcG9ydF9ncm91cCA9PSAi6Ieq55Sx5rCR5Li75YWaIiksCiAgICBwYW5lbF90aXRsZSA9IG1ha2Vfc3VwcG9ydF9ncm91cF90aXRsZSgi6Ieq55Sx5rCR5Li75YWaIiksCiAgICBiYXNlX3NpemUgPSAxMCwKICAgIHNob3dfeV90aXRsZSA9IFRSVUUsCiAgICBzaG93X3hfdGl0bGUgPSBUUlVFCiAgKQoKICBwX3BhcnR5X21hdGNoX2NociA8LSBtYWtlX3BhcnR5X21hdGNoX3BhbmVsX3Bsb3QoCiAgICBwYXJ0eV9tYXRjaF9zdWJncm91cF9jb2VmX2RmICU+JQogICAgICBmaWx0ZXIoc3VwcG9ydF9ncm91cCA9PSAi5Lit6YGT5pS56Z2p6YCj5ZCIIiksCiAgICBwYW5lbF90aXRsZSA9IG1ha2Vfc3VwcG9ydF9ncm91cF90aXRsZSgi5Lit6YGT5pS56Z2p6YCj5ZCIIiksCiAgICBiYXNlX3NpemUgPSAxMCwKICAgIHNob3dfeV90aXRsZSA9IEZBTFNFLAogICAgc2hvd194X3RpdGxlID0gVFJVRQogICkKCiAgcF9wYXJ0eV9tYXRjaF9jZHAgPC0gbWFrZV9wYXJ0eV9tYXRjaF9wYW5lbF9wbG90KAogICAgcGFydHlfbWF0Y2hfc3ViZ3JvdXBfY29lZl9kZiAlPiUKICAgICAgZmlsdGVyKHN1cHBvcnRfZ3JvdXAgPT0gIueri+aGsuawkeS4u+WFmiIpLAogICAgcGFuZWxfdGl0bGUgPSBtYWtlX3N1cHBvcnRfZ3JvdXBfdGl0bGUoIueri+aGsuawkeS4u+WFmiIpLAogICAgYmFzZV9zaXplID0gMTAsCiAgICBzaG93X3lfdGl0bGUgPSBGQUxTRSwKICAgIHNob3dfeF90aXRsZSA9IFRSVUUKICApCgogIHBfcGFydHlfbWF0Y2hfc2Fuc2VpIDwtIG1ha2VfcGFydHlfbWF0Y2hfcGFuZWxfcGxvdCgKICAgIHBhcnR5X21hdGNoX3N1Ymdyb3VwX2NvZWZfZGYgJT4lCiAgICAgIGZpbHRlcihzdXBwb3J0X2dyb3VwID09ICLlj4LmlL/lhZoiKSwKICAgIHBhbmVsX3RpdGxlID0gbWFrZV9zdXBwb3J0X2dyb3VwX3RpdGxlKCLlj4LmlL/lhZoiKSwKICAgIGJhc2Vfc2l6ZSA9IDEwLAogICAgc2hvd195X3RpdGxlID0gRkFMU0UsCiAgICBzaG93X3hfdGl0bGUgPSBUUlVFCiAgKQoKICBwX3BhcnR5X21hdGNoX2JvdHRvbSA8LQogICAgcF9wYXJ0eV9tYXRjaF9sZHAgKwogICAgcF9wYXJ0eV9tYXRjaF9jaHIgKwogICAgcF9wYXJ0eV9tYXRjaF9jZHAgKwogICAgcF9wYXJ0eV9tYXRjaF9zYW5zZWkgKwogICAgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gNCkKCiAgcF9wYXJ0eV9tYXRjaCA8LQogICAgcF9wYXJ0eV9tYXRjaF9vdmVyYWxsIC8KICAgIHBfcGFydHlfbWF0Y2hfYm90dG9tICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoCiAgICAgIGhlaWdodHMgPSBjKDEuMjUsIDEpCiAgICApCgogIHByaW50KHBfcGFydHlfbWF0Y2gpCgogIHNhdmVfcGxvdCgKICAgICJwYXJ0eV9tYXRjaF9lZmZlY3RfY29tYmluZWQucG5nIiwKICAgIHBfcGFydHlfbWF0Y2gsCiAgICB3aWR0aCA9IDE0LAogICAgaGVpZ2h0ID0gOC44CiAgKQoKCiAgcmVsYXRpdmVfY3VlX21hcCA8LSBjKAogICAgcGFydHlfbmFtZSA9ICJwYXJ0eSIsCiAgICBnZHBfZ3Jvd3RoID0gImVjb25vbWljIiwKICAgIG5pa2tlaSA9ICJlY29ub21pYyIsCiAgICBjcGkgPSAiZWNvbm9taWMiLAogICAgdW5lbXBsb3ltZW50ID0gImVjb25vbWljIgogICkKCiAgbWVhbl9hYnNvbHV0ZV9wYWlyd2lzZV9kaWZmZXJlbmNlIDwtIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0geFtpcy5maW5pdGUoeCldCgogICAgaWYgKGxlbmd0aCh4KSA8IDIpIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHBhaXJ3aXNlX2RpZmZlcmVuY2VzIDwtIGNvbWJuKAogICAgICB4LAogICAgICAyLAogICAgICBGVU4gPSBmdW5jdGlvbih6KSBhYnMoelsxXSAtIHpbMl0pCiAgICApCgogICAgbWVhbihwYWlyd2lzZV9kaWZmZXJlbmNlcykKICB9CgogIGxpbmVhcl9zbG9wZSA8LSBmdW5jdGlvbih5LCB4KSB7CiAgICBrZWVwIDwtIGlzLmZpbml0ZSh5KSAmIGlzLmZpbml0ZSh4KQogICAgeSA8LSB5W2tlZXBdCiAgICB4IDwtIHhba2VlcF0KCiAgICBpZiAobGVuZ3RoKHkpIDwgMiB8fCBsZW5ndGgodW5pcXVlKHgpKSA8IDIpIHsKICAgICAgcmV0dXJuKE5BX3JlYWxfKQogICAgfQoKICAgIHVubmFtZShjb2VmKGxtKHkgfiB4KSlbMl0pCiAgfQoKICBib290c3RyYXBfdHdvX3NpZGVkX3AgPC0gZnVuY3Rpb24oeCkgewogICAgeCA8LSB4W2lzLmZpbml0ZSh4KV0KICAgIEJfdmFsaWQgPC0gbGVuZ3RoKHgpCgogICAgaWYgKEJfdmFsaWQgPT0gMCkgewogICAgICByZXR1cm4oTkFfcmVhbF8pCiAgICB9CgogICAgcF9sb3dlciA8LSAoMSArIHN1bSh4IDw9IDApKSAvIChCX3ZhbGlkICsgMSkKICAgIHBfdXBwZXIgPC0gKDEgKyBzdW0oeCA+PSAwKSkgLyAoQl92YWxpZCArIDEpCgogICAgbWluKDEsIDIgKiBtaW4ocF9sb3dlciwgcF91cHBlcikpCiAgfQoKICBzYWZlX3F1YW50aWxlIDwtIGZ1bmN0aW9uKHgsIHByb2JhYmlsaXR5KSB7CiAgICB4IDwtIHhbaXMuZmluaXRlKHgpXQoKICAgIGlmIChsZW5ndGgoeCkgPT0gMCkgewogICAgICByZXR1cm4oTkFfcmVhbF8pCiAgICB9CgogICAgdW5uYW1lKAogICAgICBxdWFudGlsZSgKICAgICAgICB4LAogICAgICAgIHByb2JzID0gcHJvYmFiaWxpdHksCiAgICAgICAgdHlwZSA9IDYsCiAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICkKICAgICkKICB9CgogIHByZXBhcmVfcmVsYXRpdmVfY3VlX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKGRhdGEsIGN1ZV9tYXApIHsKICAgIGF0dHJpYnV0ZXMgPC0gbmFtZXMoY3VlX21hcCkKCiAgICByZXF1aXJlZF9jb2x1bW5zIDwtIGMoCiAgICAgICJJRCIsCiAgICAgICJwYXJ0eV9uIiwKICAgICAgInNlbGVjdGVkIiwKICAgICAgYXR0cmlidXRlcwogICAgKQoKICAgIG1pc3NpbmdfY29sdW1ucyA8LSBzZXRkaWZmKAogICAgICByZXF1aXJlZF9jb2x1bW5zLAogICAgICBuYW1lcyhkYXRhKQogICAgKQoKICAgIGlmIChsZW5ndGgobWlzc2luZ19jb2x1bW5zKSA+IDApIHsKICAgICAgc3RvcCgiQ2hlY2sgcmVsYXRpdmUgd2VpZ2h0IikKICAgIH0KCiAgICBpZiAoIWFsbCh1bm5hbWUoY3VlX21hcCkgJWluJSBjKCJwYXJ0eSIsICJlY29ub21pYyIpKSkgewogICAgICBzdG9wKCJDaGVjayByZWxhdGl2ZSB3ZWlnaHQiKQogICAgfQoKICAgIGFuYWx5c2lzX2RhdGEgPC0gZGF0YSAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIElELAogICAgICAgIHBhcnR5X24sCiAgICAgICAgc2VsZWN0ZWQsCiAgICAgICAgYWxsX29mKGF0dHJpYnV0ZXMpCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCiAgICAgICAgcGFydHlfbiA9IGFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHBhcnR5X24pKSwKICAgICAgICBzZWxlY3RlZCA9IGFzLmludGVnZXIoc2VsZWN0ZWQpLAogICAgICAgIGFjcm9zcygKICAgICAgICAgIGFsbF9vZihhdHRyaWJ1dGVzKSwKICAgICAgICAgIGFzLmNoYXJhY3RlcgogICAgICAgICkKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKAogICAgICAgICFpcy5uYShJRCksCiAgICAgICAgcGFydHlfbiAlaW4lIDI6NSwKICAgICAgICBzZWxlY3RlZCAlaW4lIGMoMEwsIDFMKQogICAgICApCgogICAgb2JzZXJ2ZWRfY29uZGl0aW9ucyA8LSBzb3J0KAogICAgICB1bmlxdWUoYW5hbHlzaXNfZGF0YSRwYXJ0eV9uKQogICAgKQoKICAgIGlmICghaWRlbnRpY2FsKG9ic2VydmVkX2NvbmRpdGlvbnMsIDI6NSkpIHsKICAgICAgc3RvcCgiQ2hlY2siKQogICAgfQoKICAgIGxvbmdfZGF0YSA8LSBhbmFseXNpc19kYXRhICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihhdHRyaWJ1dGVzKSwKICAgICAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLAogICAgICAgIHZhbHVlc190byA9ICJsZXZlbCIKICAgICAgKSAlPiUKICAgICAgZmlsdGVyKAogICAgICAgICFpcy5uYShsZXZlbCksCiAgICAgICAgbGV2ZWwgIT0gIiIKICAgICAgKQoKICAgIGV4cGVjdGVkX2NlbGxzIDwtIGxvbmdfZGF0YSAlPiUKICAgICAgZGlzdGluY3QoCiAgICAgICAgYXR0cmlidXRlLAogICAgICAgIGxldmVsCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBhdHRyaWJ1dGVfb3JkZXIgPSBtYXRjaCgKICAgICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICAgIGF0dHJpYnV0ZXMKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgIGFycmFuZ2UoCiAgICAgICAgYXR0cmlidXRlX29yZGVyLAogICAgICAgIGF0dHJpYnV0ZSwKICAgICAgICBsZXZlbAogICAgICApICU+JQogICAgICBzZWxlY3QoLWF0dHJpYnV0ZV9vcmRlcikgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBjZWxsX2tleSA9IHBhc3RlKAogICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgbGV2ZWwsCiAgICAgICAgICBzZXAgPSAiXHIiCiAgICAgICAgKQogICAgICApCgogICAgcmVzcG9uZGVudF9jZWxsIDwtIGxvbmdfZGF0YSAlPiUKICAgICAgZ3JvdXBfYnkoCiAgICAgICAgcGFydHlfbiwKICAgICAgICBJRCwKICAgICAgICBhdHRyaWJ1dGUsCiAgICAgICAgbGV2ZWwKICAgICAgKSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIHlfc3VtID0gc3VtKHNlbGVjdGVkKSwKICAgICAgICBuX29icyA9IG4oKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIG11dGF0ZSgKICAgICAgICBjZWxsX2tleSA9IHBhc3RlKAogICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgbGV2ZWwsCiAgICAgICAgICBzZXAgPSAiXHIiCiAgICAgICAgKQogICAgICApCgogICAgY29uZGl0aW9uX29iamVjdHMgPC0gbGFwcGx5KAogICAgICAyOjUsCiAgICAgIGZ1bmN0aW9uKG5fdmFsdWUpIHsKICAgICAgICBjb25kaXRpb25fZGF0YSA8LSByZXNwb25kZW50X2NlbGwgJT4lCiAgICAgICAgICBmaWx0ZXIoCiAgICAgICAgICAgIHBhcnR5X24gPT0gbl92YWx1ZQogICAgICAgICAgKQoKICAgICAgICBpZF92YWx1ZXMgPC0gc29ydCgKICAgICAgICAgIHVuaXF1ZShjb25kaXRpb25fZGF0YSRJRCkKICAgICAgICApCiAgICAgICAgbl9pZHMgPC0gbGVuZ3RoKGlkX3ZhbHVlcykKICAgICAgICBuX2NlbGxzIDwtIG5yb3coZXhwZWN0ZWRfY2VsbHMpCgogICAgICAgIGlmIChuX2lkcyA9PSAwKSB7CiAgICAgICAgICBzdG9wKCJDaGVjayIpCiAgICAgICAgfQoKICAgICAgICB5X21hdHJpeCA8LSBtYXRyaXgoCiAgICAgICAgICAwLAogICAgICAgICAgbnJvdyA9IG5faWRzLAogICAgICAgICAgbmNvbCA9IG5fY2VsbHMsCiAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoCiAgICAgICAgICAgIGlkX3ZhbHVlcywKICAgICAgICAgICAgZXhwZWN0ZWRfY2VsbHMkY2VsbF9rZXkKICAgICAgICAgICkKICAgICAgICApCgogICAgICAgIG5fbWF0cml4IDwtIG1hdHJpeCgKICAgICAgICAgIDAsCiAgICAgICAgICBucm93ID0gbl9pZHMsCiAgICAgICAgICBuY29sID0gbl9jZWxscywKICAgICAgICAgIGRpbW5hbWVzID0gbGlzdCgKICAgICAgICAgICAgaWRfdmFsdWVzLAogICAgICAgICAgICBleHBlY3RlZF9jZWxscyRjZWxsX2tleQogICAgICAgICAgKQogICAgICAgICkKCiAgICAgICAgcm93X2luZGV4IDwtIG1hdGNoKAogICAgICAgICAgY29uZGl0aW9uX2RhdGEkSUQsCiAgICAgICAgICBpZF92YWx1ZXMKICAgICAgICApCiAgICAgICAgY29sdW1uX2luZGV4IDwtIG1hdGNoKAogICAgICAgICAgY29uZGl0aW9uX2RhdGEkY2VsbF9rZXksCiAgICAgICAgICBleHBlY3RlZF9jZWxscyRjZWxsX2tleQogICAgICAgICkKCiAgICAgICAgeV9tYXRyaXhbY2JpbmQocm93X2luZGV4LCBjb2x1bW5faW5kZXgpXSA8LQogICAgICAgICAgY29uZGl0aW9uX2RhdGEkeV9zdW0KICAgICAgICBuX21hdHJpeFtjYmluZChyb3dfaW5kZXgsIGNvbHVtbl9pbmRleCldIDwtCiAgICAgICAgICBjb25kaXRpb25fZGF0YSRuX29icwoKICAgICAgICBpZiAoYW55KGNvbFN1bXMobl9tYXRyaXgpID09IDApKSB7CiAgICAgICAgICBtaXNzaW5nX2NlbGxzIDwtIGV4cGVjdGVkX2NlbGxzJGNlbGxfa2V5WwogICAgICAgICAgICBjb2xTdW1zKG5fbWF0cml4KSA9PSAwCiAgICAgICAgICBdCgogICAgICAgICAgc3RvcCgiQ2hlY2sgYXR0cmlidXRlcyIpCiAgICAgICAgfQoKICAgICAgICBsaXN0KAogICAgICAgICAgcGFydHlfbiA9IG5fdmFsdWUsCiAgICAgICAgICBpZHMgPSBpZF92YWx1ZXMsCiAgICAgICAgICBjZWxsX2luZm8gPSBleHBlY3RlZF9jZWxscywKICAgICAgICAgIHlfbWF0cml4ID0geV9tYXRyaXgsCiAgICAgICAgICBuX21hdHJpeCA9IG5fbWF0cml4CiAgICAgICAgKQogICAgICB9CiAgICApCgogICAgbmFtZXMoY29uZGl0aW9uX29iamVjdHMpIDwtIGFzLmNoYXJhY3RlcigyOjUpCgogICAgbGlzdCgKICAgICAgY3VlX21hcCA9IGN1ZV9tYXAsCiAgICAgIGF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzLAogICAgICBjb25kaXRpb25zID0gY29uZGl0aW9uX29iamVjdHMKICAgICkKICB9CgogIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzIDwtIGZ1bmN0aW9uKAogICAgICBwcmVwYXJlZCwKICAgICAgY2x1c3Rlcl93ZWlnaHRzID0gTlVMTAogICkgewogICAgY29uZGl0aW9uX3Jlc3VsdHMgPC0gbGFwcGx5KAogICAgICBuYW1lcyhwcmVwYXJlZCRjb25kaXRpb25zKSwKICAgICAgZnVuY3Rpb24oY29uZGl0aW9uX25hbWUpIHsKICAgICAgICBvYmplY3QgPC0gcHJlcGFyZWQkY29uZGl0aW9uc1tbY29uZGl0aW9uX25hbWVdXQoKICAgICAgICBpZiAoaXMubnVsbChjbHVzdGVyX3dlaWdodHMpKSB7CiAgICAgICAgICB3ZWlnaHRzIDwtIHJlcCgKICAgICAgICAgICAgMSwKICAgICAgICAgICAgbGVuZ3RoKG9iamVjdCRpZHMpCiAgICAgICAgICApCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHdlaWdodHMgPC0gY2x1c3Rlcl93ZWlnaHRzW1tjb25kaXRpb25fbmFtZV1dCiAgICAgICAgfQoKICAgICAgICBpZiAobGVuZ3RoKHdlaWdodHMpICE9IGxlbmd0aChvYmplY3QkaWRzKSkgewogICAgICAgICAgc3RvcCgiQ2hlY2siKQogICAgICAgIH0KCiAgICAgICAgbnVtZXJhdG9yIDwtIGFzLm51bWVyaWMoCiAgICAgICAgICBjcm9zc3Byb2QoCiAgICAgICAgICAgIHdlaWdodHMsCiAgICAgICAgICAgIG9iamVjdCR5X21hdHJpeAogICAgICAgICAgKQogICAgICAgICkKCiAgICAgICAgZGVub21pbmF0b3IgPC0gYXMubnVtZXJpYygKICAgICAgICAgIGNyb3NzcHJvZCgKICAgICAgICAgICAgd2VpZ2h0cywKICAgICAgICAgICAgb2JqZWN0JG5fbWF0cml4CiAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBpZiAoYW55KGRlbm9taW5hdG9yIDw9IDApKSB7CiAgICAgICAgICBzdG9wKCJDaGVjayBhdHRyaWJ1dGVzIikKICAgICAgICB9CgogICAgICAgIG1hcmdpbmFsX21lYW5zIDwtIG51bWVyYXRvciAvIGRlbm9taW5hdG9yCgogICAgICAgIG1tX3RhYmxlIDwtIG9iamVjdCRjZWxsX2luZm8gJT4lCiAgICAgICAgICB0cmFuc211dGUoCiAgICAgICAgICAgIHBhcnR5X24gPSBvYmplY3QkcGFydHlfbiwKICAgICAgICAgICAgYXR0cmlidXRlLAogICAgICAgICAgICBsZXZlbCwKICAgICAgICAgICAgbWFyZ2luYWxfbWVhbiA9IG1hcmdpbmFsX21lYW5zCiAgICAgICAgICApCgogICAgICAgIGF0dHJpYnV0ZV90YWJsZSA8LSBtbV90YWJsZSAlPiUKICAgICAgICAgIGdyb3VwX2J5KAogICAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgICBhdHRyaWJ1dGUKICAgICAgICAgICkgJT4lCiAgICAgICAgICBzdW1tYXJpc2UoCiAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgICAgICAgIG1lYW5fYWJzb2x1dGVfcGFpcndpc2VfZGlmZmVyZW5jZSgKICAgICAgICAgICAgICAgIG1hcmdpbmFsX21lYW4KICAgICAgICAgICAgICApLAogICAgICAgICAgICBuX2xldmVscyA9IG4oKSwKICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICAgICAgKSAlPiUKICAgICAgICAgIG11dGF0ZSgKICAgICAgICAgICAgY3VlX2ZhbWlseSA9IHVubmFtZSgKICAgICAgICAgICAgICBwcmVwYXJlZCRjdWVfbWFwW2F0dHJpYnV0ZV0KICAgICAgICAgICAgKSwKICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5ID0gMSAvIHBhcnR5X24sCiAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UgLwogICAgICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5CiAgICAgICAgICApCgogICAgICAgIGN1ZV90YWJsZV9sb25nIDwtIGF0dHJpYnV0ZV90YWJsZSAlPiUKICAgICAgICAgIGdyb3VwX2J5KAogICAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgICBjdWVfZmFtaWx5CiAgICAgICAgICApICU+JQogICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlID0gbWVhbigKICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICApLAogICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0gbWVhbigKICAgICAgICAgICAgICBpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICApLAogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICAgICApCgogICAgICAgIHBhcnR5X3RhYmxlIDwtIGN1ZV90YWJsZV9sb25nICU+JQogICAgICAgICAgZmlsdGVyKAogICAgICAgICAgICBjdWVfZmFtaWx5ID09ICJwYXJ0eSIKICAgICAgICAgICkgJT4lCiAgICAgICAgICB0cmFuc211dGUoCiAgICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICAgICAgIGltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQKICAgICAgICAgICkKCiAgICAgICAgZWNvbm9taWNfdGFibGUgPC0gY3VlX3RhYmxlX2xvbmcgJT4lCiAgICAgICAgICBmaWx0ZXIoCiAgICAgICAgICAgIGN1ZV9mYW1pbHkgPT0gImVjb25vbWljIgogICAgICAgICAgKSAlPiUKICAgICAgICAgIHRyYW5zbXV0ZSgKICAgICAgICAgICAgcGFydHlfbiwKICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSA9CiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgICAgICAgaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZAogICAgICAgICAgKQoKICAgICAgICBjdWVfdGFibGUgPC0gZnVsbF9qb2luKAogICAgICAgICAgcGFydHlfdGFibGUsCiAgICAgICAgICBlY29ub21pY190YWJsZSwKICAgICAgICAgIGJ5ID0gInBhcnR5X24iCiAgICAgICAgKSAlPiUKICAgICAgICAgIG11dGF0ZSgKICAgICAgICAgICAgYmFzZWxpbmVfc2VsZWN0aW9uX3Byb2JhYmlsaXR5ID0gMSAvIHBhcnR5X24sCgogICAgICAgICAgICB0b3RhbF9pbXBvcnRhbmNlX3BhaXJ3aXNlID0KICAgICAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlICsKICAgICAgICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlLAoKICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCArCiAgICAgICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKCiAgICAgICAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSA9IGlmX2Vsc2UoCiAgICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZSA+IDAsCiAgICAgICAgICAgICAgcGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSAvCiAgICAgICAgICAgICAgICB0b3RhbF9pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgICAgIE5BX3JlYWxfCiAgICAgICAgICAgICksCgogICAgICAgICAgICByZWxhdGl2ZV9lY29ub21pY193ZWlnaHRfcGFpcndpc2UgPQogICAgICAgICAgICAgIDEgLSByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UsCgogICAgICAgICAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2VfYWRqdXN0ZWQgPSBpZl9lbHNlKAogICAgICAgICAgICAgIHRvdGFsX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPiAwLAogICAgICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgLwogICAgICAgICAgICAgICAgdG90YWxfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCwKICAgICAgICAgICAgICBOQV9yZWFsXwogICAgICAgICAgICApLAoKICAgICAgICAgICAgcmVsYXRpdmVfZWNvbm9taWNfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAgICAgICAxIC0gcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlX2FkanVzdGVkLAoKICAgICAgICAgICAgYWRqdXN0bWVudF9pZGVudGl0eV9kaWZmZXJlbmNlID0KICAgICAgICAgICAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2VfYWRqdXN0ZWQgLQogICAgICAgICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlCiAgICAgICAgICApCgogICAgICAgIGlmICgKICAgICAgICAgIGFueSgKICAgICAgICAgICAgYWJzKGN1ZV90YWJsZSRhZGp1c3RtZW50X2lkZW50aXR5X2RpZmZlcmVuY2UpID4gMWUtMTAsCiAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgKQogICAgICAgICkgewogICAgICAgICAgc3RvcCgiQ2hlY2sgcmVsYXRpdmUgd2VpZ2h0IikKICAgICAgICB9CgogICAgICAgIGxpc3QoCiAgICAgICAgICBtYXJnaW5hbF9tZWFucyA9IG1tX3RhYmxlLAogICAgICAgICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPSBhdHRyaWJ1dGVfdGFibGUsCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSA9IGN1ZV90YWJsZQogICAgICAgICkKICAgICAgfQogICAgKQoKICAgIGxpc3QoCiAgICAgIG1hcmdpbmFsX21lYW5zID0gYmluZF9yb3dzKAogICAgICAgIGxhcHBseSgKICAgICAgICAgIGNvbmRpdGlvbl9yZXN1bHRzLAogICAgICAgICAgZnVuY3Rpb24oeCkgeCRtYXJnaW5hbF9tZWFucwogICAgICAgICkKICAgICAgKSwKICAgICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPSBiaW5kX3Jvd3MoCiAgICAgICAgbGFwcGx5KAogICAgICAgICAgY29uZGl0aW9uX3Jlc3VsdHMsCiAgICAgICAgICBmdW5jdGlvbih4KSB4JGF0dHJpYnV0ZV9pbXBvcnRhbmNlCiAgICAgICAgKQogICAgICApLAogICAgICBjdWVfaW1wb3J0YW5jZSA9IGJpbmRfcm93cygKICAgICAgICBsYXBwbHkoCiAgICAgICAgICBjb25kaXRpb25fcmVzdWx0cywKICAgICAgICAgIGZ1bmN0aW9uKHgpIHgkY3VlX2ltcG9ydGFuY2UKICAgICAgICApCiAgICAgICkgJT4lCiAgICAgICAgYXJyYW5nZShwYXJ0eV9uKQogICAgKQogIH0KCiAgZXN0aW1hdGVfcmVsYXRpdmVfY3VlX3Nsb3BlcyA8LSBmdW5jdGlvbihjdWVfaW1wb3J0YW5jZSkgewogICAgY3VlX2ltcG9ydGFuY2UgPC0gY3VlX2ltcG9ydGFuY2UgJT4lCiAgICAgIGFycmFuZ2UocGFydHlfbikKCiAgICBpZiAoIWlkZW50aWNhbChjdWVfaW1wb3J0YW5jZSRwYXJ0eV9uLCAyOjUpKSB7CiAgICAgIHN0b3AoIkNoZWNrIHJlbGF0aXZlIHdlaWdodCIpCiAgICB9CgogICAgeCA8LSBjdWVfaW1wb3J0YW5jZSRwYXJ0eV9uCgogICAgYygKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlID0KICAgICAgICBsaW5lYXJfc2xvcGUoCiAgICAgICAgICBjdWVfaW1wb3J0YW5jZSRyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICB4CiAgICAgICAgKSwKCiAgICAgIGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgIGxpbmVhcl9zbG9wZSgKICAgICAgICAgIGN1ZV9pbXBvcnRhbmNlJGVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICB4CiAgICAgICAgKQogICAgKQogIH0KCiAgcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAgPC0gZnVuY3Rpb24oCiAgICAgIHByZXBhcmVkLAogICAgICBCLAogICAgICBzZWVkLAogICAgICBwcm9ncmVzc19ldmVyeSA9IDEwMAogICkgewogICAgc2V0LnNlZWQoc2VlZCkKCiAgICBjb25kaXRpb25fcmVzdWx0cyA8LSB2ZWN0b3IoCiAgICAgICJsaXN0IiwKICAgICAgQgogICAgKQoKICAgIHNsb3BlX25hbWVzIDwtIGMoCiAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiLAogICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiwKICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICkKCiAgICBzbG9wZV9tYXRyaXggPC0gbWF0cml4KAogICAgICBOQV9yZWFsXywKICAgICAgbnJvdyA9IEIsCiAgICAgIG5jb2wgPSBsZW5ndGgoc2xvcGVfbmFtZXMpLAogICAgICBkaW1uYW1lcyA9IGxpc3QoCiAgICAgICAgTlVMTCwKICAgICAgICBzbG9wZV9uYW1lcwogICAgICApCiAgICApCgogICAgZm9yIChiIGluIHNlcV9sZW4oQikpIHsKICAgICAgY2x1c3Rlcl93ZWlnaHRzIDwtIGxhcHBseSgKICAgICAgICBwcmVwYXJlZCRjb25kaXRpb25zLAogICAgICAgIGZ1bmN0aW9uKG9iamVjdCkgewogICAgICAgICAgbl9pZHMgPC0gbGVuZ3RoKG9iamVjdCRpZHMpCgogICAgICAgICAgc2FtcGxlZF9wb3NpdGlvbnMgPC0gc2FtcGxlLmludCgKICAgICAgICAgICAgbiA9IG5faWRzLAogICAgICAgICAgICBzaXplID0gbl9pZHMsCiAgICAgICAgICAgIHJlcGxhY2UgPSBUUlVFCiAgICAgICAgICApCgogICAgICAgICAgdGFidWxhdGUoCiAgICAgICAgICAgIHNhbXBsZWRfcG9zaXRpb25zLAogICAgICAgICAgICBuYmlucyA9IG5faWRzCiAgICAgICAgICApCiAgICAgICAgfQogICAgICApCgogICAgICBib290c3RyYXBfZXN0aW1hdGVzIDwtIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzKAogICAgICAgIHByZXBhcmVkID0gcHJlcGFyZWQsCiAgICAgICAgY2x1c3Rlcl93ZWlnaHRzID0gY2x1c3Rlcl93ZWlnaHRzCiAgICAgICkKCiAgICAgIGNvbmRpdGlvbl9yZXN1bHRzW1tiXV0gPC0KICAgICAgICBib290c3RyYXBfZXN0aW1hdGVzJGN1ZV9pbXBvcnRhbmNlICU+JQogICAgICAgIHNlbGVjdCgKICAgICAgICAgIHBhcnR5X24sCiAgICAgICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlLAogICAgICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSwKICAgICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQsCiAgICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkLAogICAgICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlCiAgICAgICAgKSAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICBib290c3RyYXBfcmVwbGljYXRpb24gPSBiLAogICAgICAgICAgLmJlZm9yZSA9IDEKICAgICAgICApCgogICAgICBzbG9wZV9tYXRyaXhbYiwgXSA8LSBlc3RpbWF0ZV9yZWxhdGl2ZV9jdWVfc2xvcGVzKAogICAgICAgIGJvb3RzdHJhcF9lc3RpbWF0ZXMkY3VlX2ltcG9ydGFuY2UKICAgICAgKQoKICAgICAgaWYgKAogICAgICAgIHByb2dyZXNzX2V2ZXJ5ID4gMCAmJgogICAgICAgIChiICUlIHByb2dyZXNzX2V2ZXJ5ID09IDAgfHwgYiA9PSBCKQogICAgICApIHsKICAgICAgICBtZXNzYWdlKCJCb290c3RyYXA6ICIsIGIsICIvIiwgQikKICAgICAgfQogICAgfQoKICAgIGxpc3QoCiAgICAgIGNvbmRpdGlvbl9lc3RpbWF0ZXMgPSBiaW5kX3Jvd3MoCiAgICAgICAgY29uZGl0aW9uX3Jlc3VsdHMKICAgICAgKSwKICAgICAgc2xvcGVzID0gYXNfdGliYmxlKAogICAgICAgIHNsb3BlX21hdHJpeAogICAgICApICU+JQogICAgICAgIG11dGF0ZSgKICAgICAgICAgIGJvb3RzdHJhcF9yZXBsaWNhdGlvbiA9IHJvd19udW1iZXIoKSwKICAgICAgICAgIC5iZWZvcmUgPSAxCiAgICAgICAgKQogICAgKQogIH0KCiAgc3VtbWFyaXNlX2NvbmRpdGlvbl9pbnRlcnZhbHMgPC0gZnVuY3Rpb24oCiAgICAgIG9ic2VydmVkX2N1ZV9pbXBvcnRhbmNlLAogICAgICBib290c3RyYXBfY29uZGl0aW9uX3Jlc3VsdHMKICApIHsKICAgIHN0YXRpc3RpY3MgPC0gYygKICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UiLAogICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwKICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIgogICAgKQoKICAgIG9ic2VydmVkX2xvbmcgPC0gb2JzZXJ2ZWRfY3VlX2ltcG9ydGFuY2UgJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBwYXJ0eV9uLAogICAgICAgIGFsbF9vZihzdGF0aXN0aWNzKQogICAgICApICU+JQogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IGFsbF9vZihzdGF0aXN0aWNzKSwKICAgICAgICBuYW1lc190byA9ICJzdGF0aXN0aWMiLAogICAgICAgIHZhbHVlc190byA9ICJlc3RpbWF0ZSIKICAgICAgKQoKICAgIGJvb3RzdHJhcF9sb25nIDwtIGJvb3RzdHJhcF9jb25kaXRpb25fcmVzdWx0cyAlPiUKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBhbGxfb2Yoc3RhdGlzdGljcyksCiAgICAgICAgbmFtZXNfdG8gPSAic3RhdGlzdGljIiwKICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiCiAgICAgICkgJT4lCiAgICAgIGdyb3VwX2J5KAogICAgICAgIHBhcnR5X24sCiAgICAgICAgc3RhdGlzdGljCiAgICAgICkgJT4lCiAgICAgIHN1bW1hcmlzZSgKICAgICAgICBjb25mX2xvdyA9IHNhZmVfcXVhbnRpbGUoCiAgICAgICAgICB2YWx1ZSwKICAgICAgICAgIDAuMDI1CiAgICAgICAgKSwKICAgICAgICBjb25mX2hpZ2ggPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgdmFsdWUsCiAgICAgICAgICAwLjk3NQogICAgICAgICksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApCgogICAgb2JzZXJ2ZWRfbG9uZyAlPiUKICAgICAgbGVmdF9qb2luKAogICAgICAgIGJvb3RzdHJhcF9sb25nLAogICAgICAgIGJ5ID0gYygKICAgICAgICAgICJwYXJ0eV9uIiwKICAgICAgICAgICJzdGF0aXN0aWMiCiAgICAgICAgKQogICAgICApCiAgfQoKICBzdW1tYXJpc2Vfc2xvcGVfaW5mZXJlbmNlIDwtIGZ1bmN0aW9uKAogICAgICBvYnNlcnZlZF9zbG9wZXMsCiAgICAgIGJvb3RzdHJhcF9zbG9wZXMKICApIHsKICAgIHN0YXRpc3RpY19uYW1lcyA8LSBuYW1lcyhvYnNlcnZlZF9zbG9wZXMpCgogICAgbWFwX2RmcigKICAgICAgc3RhdGlzdGljX25hbWVzLAogICAgICBmdW5jdGlvbihzdGF0aXN0aWNfbmFtZSkgewogICAgICAgIGJvb3RzdHJhcF92YWx1ZXMgPC0gYm9vdHN0cmFwX3Nsb3Blc1tbc3RhdGlzdGljX25hbWVdXQogICAgICAgIGJvb3RzdHJhcF92YWx1ZXMgPC0gYm9vdHN0cmFwX3ZhbHVlc1sKICAgICAgICAgIGlzLmZpbml0ZShib290c3RyYXBfdmFsdWVzKQogICAgICAgIF0KCiAgICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uIDwtIGNhc2Vfd2hlbigKICAgICAgICAgIHN0YXRpc3RpY19uYW1lID09CiAgICAgICAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiB+ICJuZWdhdGl2ZSIsCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSAlaW4lIGMoCiAgICAgICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlIiwKICAgICAgICAgICAgInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIsCiAgICAgICAgICAgICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIgogICAgICAgICAgKSB+ICJwb3NpdGl2ZSIsCiAgICAgICAgICBUUlVFIH4gIm5vbmUiCiAgICAgICAgKQoKICAgICAgICBhbmFseXNpc19yb2xlIDwtIGNhc2Vfd2hlbigKICAgICAgICAgIHN0YXRpc3RpY19uYW1lICVpbiUgYygKICAgICAgICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAgICAgICAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIKICAgICAgICAgICkgfiAiZXhwbG9yYXRvcnlfY2hvaWNlX3NldF9hZGp1c3RlZCIsCiAgICAgICAgICBzdGF0aXN0aWNfbmFtZSA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIiB+CiAgICAgICAgICAgICJkZXJpdmVkX3JlbGF0aXZlX3NoYXJlIiwKICAgICAgICAgIFRSVUUgfiAibWFudXNjcmlwdF9wcmltYXJ5X3VuYWRqdXN0ZWQiCiAgICAgICAgKQoKICAgICAgICBlc3RpbWF0ZSA8LSB1bm5hbWUoCiAgICAgICAgICBvYnNlcnZlZF9zbG9wZXNbW3N0YXRpc3RpY19uYW1lXV0KICAgICAgICApCgogICAgICAgIHRpYmJsZSgKICAgICAgICAgIHN0dWR5ID0gIlN0dWR5IDMiLAogICAgICAgICAgc3RhdGlzdGljID0gc3RhdGlzdGljX25hbWUsCiAgICAgICAgICBlc3RpbWF0ZSA9IGVzdGltYXRlLAogICAgICAgICAgY29uZl9sb3cgPSBzYWZlX3F1YW50aWxlKAogICAgICAgICAgICBib290c3RyYXBfdmFsdWVzLAogICAgICAgICAgICAwLjAyNQogICAgICAgICAgKSwKICAgICAgICAgIGNvbmZfaGlnaCA9IHNhZmVfcXVhbnRpbGUoCiAgICAgICAgICAgIGJvb3RzdHJhcF92YWx1ZXMsCiAgICAgICAgICAgIDAuOTc1CiAgICAgICAgICApLAogICAgICAgICAgcF92YWx1ZV90d29fc2lkZWQgPQogICAgICAgICAgICBib290c3RyYXBfdHdvX3NpZGVkX3AoCiAgICAgICAgICAgICAgYm9vdHN0cmFwX3ZhbHVlcwogICAgICAgICAgICApLAogICAgICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uID0gZXhwZWN0ZWRfZGlyZWN0aW9uLAogICAgICAgICAgYW5hbHlzaXNfcm9sZSA9IGFuYWx5c2lzX3JvbGUsCiAgICAgICAgICBlc3RpbWF0ZV9pbl9leHBlY3RlZF9kaXJlY3Rpb24gPSBjYXNlX3doZW4oCiAgICAgICAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA9PSAicG9zaXRpdmUiIH4gZXN0aW1hdGUgPiAwLAogICAgICAgICAgICBleHBlY3RlZF9kaXJlY3Rpb24gPT0gIm5lZ2F0aXZlIiB+IGVzdGltYXRlIDwgMCwKICAgICAgICAgICAgVFJVRSB+IE5BCiAgICAgICAgICApCiAgICAgICAgKQogICAgICB9CiAgICApCiAgfQoKICByZWxhdGl2ZV9jdWVfcHJlcGFyZWQgPC0gcHJlcGFyZV9yZWxhdGl2ZV9jdWVfYW5hbHlzaXMoCiAgICBkYXRhID0gY29uam9pbnRfYWxsX20sCiAgICBjdWVfbWFwID0gcmVsYXRpdmVfY3VlX21hcAogICkKCiAgcmVsYXRpdmVfY3VlX29ic2VydmVkIDwtIGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9pbmRpY2VzKAogICAgcHJlcGFyZWQgPSByZWxhdGl2ZV9jdWVfcHJlcGFyZWQKICApCgogIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZF9zbG9wZXMgPC0gZXN0aW1hdGVfcmVsYXRpdmVfY3VlX3Nsb3BlcygKICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZQogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRtYXJnaW5hbF9tZWFucywKICAgICJzdHVkeTNfcmVsYXRpdmVfY3VlX21hcmdpbmFsX21lYW5zLmNzdiIKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkYXR0cmlidXRlX2ltcG9ydGFuY2UsCiAgICAic3R1ZHkzX3JlbGF0aXZlX2N1ZV9hdHRyaWJ1dGVfaW1wb3J0YW5jZS5jc3YiCiAgKQoKICB3cml0ZV9jc3Zfc2FmZWx5KAogICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJGN1ZV9pbXBvcnRhbmNlLAogICAgInN0dWR5M19yZWxhdGl2ZV9jdWVfaW1wb3J0YW5jZV9hbmRfd2VpZ2h0LmNzdiIKICApCgogIHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSA8LSBmaWxlLnBhdGgoCiAgICBvdXRwdXRfZGlyLAogICAgcGFzdGUwKAogICAgICAic3R1ZHkzX3JlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwXyIsCiAgICAgIHVuaWZpZWRfY29uZmlnJGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uLAogICAgICAiX0IiLAogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgICIuY3N2IgogICAgKQogICkKCiAgcmVsYXRpdmVfc2xvcGVfYm9vdHN0cmFwX2ZpbGUgPC0gZmlsZS5wYXRoKAogICAgb3V0cHV0X2RpciwKICAgIHBhc3RlMCgKICAgICAgInN0dWR5M19yZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwXyIsCiAgICAgIHVuaWZpZWRfY29uZmlnJGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uLAogICAgICAiX0IiLAogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgICIuY3N2IgogICAgKQogICkKCiAgdXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCA8LQogICAgIXJlcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAgJiYKICAgIGZpbGUuZXhpc3RzKHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSkgJiYKICAgIGZpbGUuZXhpc3RzKHJlbGF0aXZlX3Nsb3BlX2Jvb3RzdHJhcF9maWxlKQoKICBpZiAodXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCkgewogICAgbWVzc2FnZSgiQm9vdHN0cmFwIGNhY2hlIikKCiAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2Jvb3RzdHJhcCA8LSByZWFkcjo6cmVhZF9jc3YoCiAgICAgIHJlbGF0aXZlX2NvbmRpdGlvbl9ib290c3RyYXBfZmlsZSwKICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRQogICAgKQoKICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9ib290c3RyYXAgPC0gcmVhZHI6OnJlYWRfY3N2KAogICAgICByZWxhdGl2ZV9zbG9wZV9ib290c3RyYXBfZmlsZSwKICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRQogICAgKQoKICAgIHNhdmVkX0JfY29uZGl0aW9uIDwtIG5fZGlzdGluY3QoCiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwJGJvb3RzdHJhcF9yZXBsaWNhdGlvbgogICAgKQogICAgc2F2ZWRfQl9zbG9wZSA8LSBuX2Rpc3RpbmN0KAogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwJGJvb3RzdHJhcF9yZXBsaWNhdGlvbgogICAgKQoKICAgIGlmICgKICAgICAgc2F2ZWRfQl9jb25kaXRpb24gIT0gcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CIHx8CiAgICAgIHNhdmVkX0Jfc2xvcGUgIT0gcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9CCiAgICApIHsKICAgICAgbWVzc2FnZSgiQm9vdHN0cmFwIGNhY2hlIikKICAgICAgdXNlX3NhdmVkX3JlbGF0aXZlX2Jvb3RzdHJhcCA8LSBGQUxTRQogICAgfQogIH0KCiAgaWYgKCF1c2Vfc2F2ZWRfcmVsYXRpdmVfYm9vdHN0cmFwKSB7CiAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwIDwtIHJ1bl9yZWxhdGl2ZV9jdWVfYm9vdHN0cmFwKAogICAgICBwcmVwYXJlZCA9IHJlbGF0aXZlX2N1ZV9wcmVwYXJlZCwKICAgICAgQiA9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQiwKICAgICAgc2VlZCA9IHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfc2VlZCwKICAgICAgcHJvZ3Jlc3NfZXZlcnkgPSByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX3Byb2dyZXNzX2V2ZXJ5CiAgICApCgogICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9ib290c3RyYXAgPC0KICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcCRjb25kaXRpb25fZXN0aW1hdGVzCgogICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2Jvb3RzdHJhcCA8LQogICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwJHNsb3BlcwoKICAgIHJlYWRyOjp3cml0ZV9jc3YoCiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwLAogICAgICByZWxhdGl2ZV9jb25kaXRpb25fYm9vdHN0cmFwX2ZpbGUKICAgICkKCiAgICByZWFkcjo6d3JpdGVfY3N2KAogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwLAogICAgICByZWxhdGl2ZV9zbG9wZV9ib290c3RyYXBfZmlsZQogICAgKQogIH0KCiAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgPC0gc3VtbWFyaXNlX2NvbmRpdGlvbl9pbnRlcnZhbHMoCiAgICBvYnNlcnZlZF9jdWVfaW1wb3J0YW5jZSA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgIGJvb3RzdHJhcF9jb25kaXRpb25fcmVzdWx0cyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25fYm9vdHN0cmFwCiAgKQoKICByZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlIDwtIHN1bW1hcmlzZV9zbG9wZV9pbmZlcmVuY2UoCiAgICBvYnNlcnZlZF9zbG9wZXMgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWRfc2xvcGVzLAogICAgYm9vdHN0cmFwX3Nsb3BlcyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9ib290c3RyYXAKICApCgogIHdyaXRlX2Nzdl9zYWZlbHkoCiAgICByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscywKICAgICJzdHVkeTNfcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMuY3N2IgogICkKCiAgd3JpdGVfY3N2X3NhZmVseSgKICAgIHJlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UsCiAgICAic3R1ZHkzX3JlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UuY3N2IgogICkKCiAgcmVsYXRpdmVfY3VlX3ByaW1hcnlfcmVzdWx0IDwtIHJlbGF0aXZlX2N1ZV9zbG9wZV9pbmZlcmVuY2UgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyA9PQogICAgICAgICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiCiAgICApCgogIGNhdCgiXG5TdHVkeSAz77ya55u45a++5q+U6YeN44Gu57ea5b2i5YK+5ZCRXG4iKQogIHByaW50KHJlbGF0aXZlX2N1ZV9wcmltYXJ5X3Jlc3VsdCkKCgogIHJlbGF0aXZlX3hfb2Zmc2V0IDwtIDAuMDc1CgogIHJlbGF0aXZlX3BhbmVsX2FfZGF0YSA8LSByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscyAlPiUKICAgIGZpbHRlcigKICAgICAgc3RhdGlzdGljICVpbiUgYygKICAgICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsCiAgICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UiCiAgICAgICkKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGN1ZV9mYW1pbHkgPSByZWNvZGUoCiAgICAgICAgc3RhdGlzdGljLAogICAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPSAi5pS/5YWa5ZCN5omL44GM44GL44KKIiwKICAgICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlID0gIue1jOa4iOaJi+OBjOOBi+OCiiIKICAgICAgKSwKICAgICAgY3VlX2ZhbWlseSA9IGZhY3RvcigKICAgICAgICBjdWVfZmFtaWx5LAogICAgICAgIGxldmVscyA9IGMoCiAgICAgICAgICAi5pS/5YWa5ZCN5omL44GM44GL44KKIiwKICAgICAgICAgICLntYzmuIjmiYvjgYzjgYvjgooiCiAgICAgICAgKQogICAgICApLAogICAgICB4X3Bsb3QgPSBjYXNlX3doZW4oCiAgICAgICAgY3VlX2ZhbWlseSA9PSAi5pS/5YWa5ZCN5omL44GM44GL44KKIiB+CiAgICAgICAgICBwYXJ0eV9uICsgcmVsYXRpdmVfeF9vZmZzZXQsCiAgICAgICAgY3VlX2ZhbWlseSA9PSAi57WM5riI5omL44GM44GL44KKIiB+CiAgICAgICAgICBwYXJ0eV9uIC0gcmVsYXRpdmVfeF9vZmZzZXQsCiAgICAgICAgVFJVRSB+IGFzLm51bWVyaWMocGFydHlfbikKICAgICAgKSwKICAgICAgdmFsdWVfbGFiZWwgPSBzcHJpbnRmKAogICAgICAgICIlLjNmIiwKICAgICAgICBlc3RpbWF0ZQogICAgICApCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2JfZGF0YSA8LSByZWxhdGl2ZV9jdWVfY29uZGl0aW9uX2ludGVydmFscyAlPiUKICAgIGZpbHRlcigKICAgICAgc3RhdGlzdGljID09CiAgICAgICAgInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIHZhbHVlX2xhYmVsID0gc3ByaW50ZigKICAgICAgICAiJS4xZiUlIiwKICAgICAgICAxMDAgKiBlc3RpbWF0ZQogICAgICApCiAgICApCgogIHJlbGF0aXZlX2FkanVzdGVkX2xhYmVsX21hcCA8LSByZWxhdGl2ZV9wYW5lbF9hX2RhdGEgJT4lCiAgICBkaXN0aW5jdCgKICAgICAgc3RhdGlzdGljLAogICAgICBjdWVfZmFtaWx5CiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBzdGF0aXN0aWMgPSBwYXN0ZTAoCiAgICAgICAgc3RhdGlzdGljLAogICAgICAgICJfYWRqdXN0ZWQiCiAgICAgICksCiAgICAgIGN1ZV9mYW1pbHkgPSBhcy5jaGFyYWN0ZXIoCiAgICAgICAgY3VlX2ZhbWlseQogICAgICApCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEgPC0gcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgJT4lCiAgICBmaWx0ZXIoCiAgICAgIHN0YXRpc3RpYyAlaW4lIGMoCiAgICAgICAgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiLAogICAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIgogICAgICApCiAgICApICU+JQogICAgbGVmdF9qb2luKAogICAgICByZWxhdGl2ZV9hZGp1c3RlZF9sYWJlbF9tYXAsCiAgICAgIGJ5ID0gInN0YXRpc3RpYyIKICAgICkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGN1ZV9mYW1pbHkgPSBmYWN0b3IoCiAgICAgICAgY3VlX2ZhbWlseSwKICAgICAgICBsZXZlbHMgPSBsZXZlbHMoCiAgICAgICAgICByZWxhdGl2ZV9wYW5lbF9hX2RhdGEkY3VlX2ZhbWlseQogICAgICAgICkKICAgICAgKSwKICAgICAgeF9wbG90ID0gaWZfZWxzZSgKICAgICAgICBhcy5pbnRlZ2VyKGN1ZV9mYW1pbHkpID09IDFMLAogICAgICAgIHBhcnR5X24gKyByZWxhdGl2ZV94X29mZnNldCwKICAgICAgICBwYXJ0eV9uIC0gcmVsYXRpdmVfeF9vZmZzZXQKICAgICAgKSwKICAgICAgdmFsdWVfbGFiZWwgPSBzcHJpbnRmKAogICAgICAgICIlLjFmJSUiLAogICAgICAgIDEwMCAqIGVzdGltYXRlCiAgICAgICkKICAgICkKCiAgcmVsYXRpdmVfY29uZGl0aW9uX3N1ZmZpeCA8LSBpZiAoCiAgICAi5pS/5YWa5ZCN5omL44GM44GL44KKIiAlaW4lCiAgICAgIGxldmVscyhyZWxhdGl2ZV9wYW5lbF9hX2RhdGEkY3VlX2ZhbWlseSkKICApIHsKICAgICLpgbjmip7ogqIiCiAgfSBlbHNlIHsKICAgICLmlL/lhZoiCiAgfQoKICByZWxhdGl2ZV9jb25kaXRpb25fYXhpc190aXRsZSA8LSBpZiAoCiAgICByZWxhdGl2ZV9jb25kaXRpb25fc3VmZml4ID09ICLpgbjmip7ogqIiCiAgKSB7CiAgICAi5pS/5rK757WM5riI54q25rOB44Gu6YG45oqe6IKi5pWwIgogIH0gZWxzZSB7CiAgICAi5pS/5YWa6YG45oqe6IKi5pWwIgogIH0KCiAgcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5IDwtIGlmICgKICAgIC5QbGF0Zm9ybSRPUy50eXBlID09ICJ3aW5kb3dzIgogICkgewogICAgIll1IEdvdGhpYyIKICB9IGVsc2UgewogICAgInNhbnMiCiAgfQoKICByZWxhdGl2ZV90aGVtZV9qYXBhbmVzZV9idyA8LSB0aGVtZV9idygKICAgIGJhc2Vfc2l6ZSA9IDEyLAogICAgYmFzZV9mYW1pbHkgPSByZWxhdGl2ZV9maWd1cmVfZm9udF9mYW1pbHkKICApICsKICAgIHRoZW1lKAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKAogICAgICAgIGxpbmV3aWR0aCA9IDAuMzAsCiAgICAgICAgY29sb3IgPSAiZ3JleTg4IgogICAgICApLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgbGluZXdpZHRoID0gMC42NSwKICAgICAgICBjb2xvciA9ICJibGFjayIKICAgICAgKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgICAgIGNvbG9yID0gImJsYWNrIgogICAgICApLAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIGNvbG9yID0gImJsYWNrIgogICAgICApLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KAogICAgICAgIHNpemUgPSAxMi41LAogICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgaGp1c3QgPSAwCiAgICAgICksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoCiAgICAgICAgc2l6ZSA9IDkuNSwKICAgICAgICBoanVzdCA9IDAsCiAgICAgICAgbWFyZ2luID0gbWFyZ2luKAogICAgICAgICAgYiA9IDgKICAgICAgICApCiAgICAgICksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLAogICAgICBsZWdlbmQua2V5LndpZHRoID0gZ3JpZDo6dW5pdCgKICAgICAgICAxLjI1LAogICAgICAgICJjbSIKICAgICAgKSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oCiAgICAgICAgOCwKICAgICAgICAxMCwKICAgICAgICA4LAogICAgICAgIDgKICAgICAgKQogICAgKQoKICByZWxhdGl2ZV9wYW5lbF9hIDwtIGdncGxvdCgKICAgIHJlbGF0aXZlX3BhbmVsX2FfZGF0YSwKICAgIGFlcygKICAgICAgeCA9IHhfcGxvdCwKICAgICAgeSA9IGVzdGltYXRlLAogICAgICBncm91cCA9IGN1ZV9mYW1pbHksCiAgICAgIGxpbmV0eXBlID0gY3VlX2ZhbWlseQogICAgKQogICkgKwogICAgZ2VvbV9saW5lKAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKAogICAgICAgIHltaW4gPSBjb25mX2xvdywKICAgICAgICB5bWF4ID0gY29uZl9oaWdoCiAgICAgICksCiAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xhYmVsKAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSB2YWx1ZV9sYWJlbAogICAgICApLAogICAgICBzaXplID0gMy41NSwKICAgICAgZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICBsYWJlbC5zaXplID0gMCwKICAgICAgbGFiZWwucGFkZGluZyA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMC4xMiwKICAgICAgICAibGluZXMiCiAgICAgICksCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICB2YWx1ZXMgPSBjKAogICAgICAgICLmlL/lhZrlkI3miYvjgYzjgYvjgooiID0gInNvbGlkIiwKICAgICAgICAi57WM5riI5omL44GM44GL44KKIiA9ICJkYXNoZWQiCiAgICAgICkKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBicmVha3MgPSAyOjUsCiAgICAgIGxhYmVscyA9IHBhc3RlMCgKICAgICAgICAyOjUsCiAgICAgICAgIumBuOaKnuiCoiIKICAgICAgKSwKICAgICAgbGltaXRzID0gYygKICAgICAgICAxLjcyLAogICAgICAgIDUuMjgKICAgICAgKQogICAgKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgIGxhYmVscyA9IGxhYmVsX251bWJlcigKICAgICAgICBhY2N1cmFjeSA9IDAuMDA1CiAgICAgICksCiAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbigKICAgICAgICBtdWx0ID0gYygKICAgICAgICAgIDAuMDcsCiAgICAgICAgICAwLjEwCiAgICAgICAgKQogICAgICApCiAgICApICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkHvvJrkuKHmiYvjgYzjgYvjgorjga7ntbblr77nmoTph43opoHluqYiLAogICAgICBzdWJ0aXRsZSA9ICIiLAogICAgICB4ID0gIuaUv+WFmumBuOaKnuiCouaVsCIsCiAgICAgIHkgPSAi5omL44GM44GL44KK6YeN6KaB5bqmIiwKICAgICAgbGluZXR5cGUgPSBOVUxMCiAgICApICsKICAgIGd1aWRlcygKICAgICAgbGluZXR5cGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIGxpbmV3aWR0aCA9IDAuOTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncKCiAgcmVsYXRpdmVfYWRqdXN0ZWRfbGluZXR5cGVzIDwtIHNldE5hbWVzKAogICAgYygKICAgICAgInNvbGlkIiwKICAgICAgImRhc2hlZCIKICAgICksCiAgICBsZXZlbHMoCiAgICAgIHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEkY3VlX2ZhbWlseQogICAgKQogICkKCiAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWQgPC0gZ2dwbG90KAogICAgcmVsYXRpdmVfcGFuZWxfYWRqdXN0ZWRfZGF0YSwKICAgIGFlcygKICAgICAgeCA9IHhfcGxvdCwKICAgICAgeSA9IGVzdGltYXRlLAogICAgICBncm91cCA9IGN1ZV9mYW1pbHksCiAgICAgIGxpbmV0eXBlID0gY3VlX2ZhbWlseQogICAgKQogICkgKwogICAgZ2VvbV9saW5lKAogICAgICBsaW5ld2lkdGggPSAwLjgwLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKAogICAgICAgIHltaW4gPSBjb25mX2xvdywKICAgICAgICB5bWF4ID0gY29uZl9oaWdoCiAgICAgICksCiAgICAgIHdpZHRoID0gMC4wNzUsCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xhYmVsKAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSB2YWx1ZV9sYWJlbAogICAgICApLAogICAgICBzaXplID0gMy41NSwKICAgICAgZmFtaWx5ID0gcmVsYXRpdmVfZmlndXJlX2ZvbnRfZmFtaWx5LAogICAgICBsYWJlbC5zaXplID0gMCwKICAgICAgbGFiZWwucGFkZGluZyA9IGdyaWQ6OnVuaXQoCiAgICAgICAgMC4xMiwKICAgICAgICAibGluZXMiCiAgICAgICksCiAgICAgIGZpbGwgPSAid2hpdGUiLAogICAgICBjb2xvciA9ICJibGFjayIKICAgICkgKwogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKAogICAgICB2YWx1ZXMgPSByZWxhdGl2ZV9hZGp1c3RlZF9saW5ldHlwZXMKICAgICkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICBicmVha3MgPSAyOjUsCiAgICAgIGxhYmVscyA9IHBhc3RlMCgKICAgICAgICAyOjUsCiAgICAgICAgcmVsYXRpdmVfY29uZGl0aW9uX3N1ZmZpeAogICAgICApLAogICAgICBsaW1pdHMgPSBjKAogICAgICAgIDEuNzIsCiAgICAgICAgNS4yOAogICAgICApCiAgICApICsKICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgbGFiZWxzID0gbGFiZWxfcGVyY2VudCgKICAgICAgICBhY2N1cmFjeSA9IDEKICAgICAgKSwKICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKAogICAgICAgIG11bHQgPSBjKAogICAgICAgICAgMC4wNywKICAgICAgICAgIDAuMTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiQe+8mumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6piIsCiAgICAgIHN1YnRpdGxlID0KICAgICAgICAi5pyq6Kq/5pW06YeN6KaB5bqmIMO3IOW5s+Wdh+mBuOaKnueiuueOh++8iDHvvI/pgbjmip7ogqLmlbDvvIkiLAogICAgICB4ID0gcmVsYXRpdmVfY29uZGl0aW9uX2F4aXNfdGl0bGUsCiAgICAgIHkgPSAi5bmz5Z2H6YG45oqe56K6546H44Gr5a++44GZ44KL5rC05rqW6ZaT5beuIiwKICAgICAgbGluZXR5cGUgPSBOVUxMCiAgICApICsKICAgIGd1aWRlcygKICAgICAgbGluZXR5cGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICAgIGxpbmV3aWR0aCA9IDAuOTAKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgcmVsYXRpdmVfdGhlbWVfamFwYW5lc2VfYncKCiAgcmVsYXRpdmVfYl9yYW5nZSA8LSByYW5nZSgKICAgIGMoCiAgICAgIHJlbGF0aXZlX3BhbmVsX2JfZGF0YSRjb25mX2xvdywKICAgICAgcmVsYXRpdmVfcGFuZWxfYl9kYXRhJGNvbmZfaGlnaCwKICAgICAgMC41CiAgICApLAogICAgbmEucm0gPSBUUlVFCiAgKQoKICByZWxhdGl2ZV9iX3BhZGRpbmcgPC0gbWF4KAogICAgMC4wMjUsCiAgICAwLjEwICogZGlmZihyZWxhdGl2ZV9iX3JhbmdlKQogICkKCiAgcmVsYXRpdmVfYl9sb3dlciA8LSBtYXgoCiAgICAwLAogICAgZmxvb3IoCiAgICAgIDIwICoKICAgICAgICAocmVsYXRpdmVfYl9yYW5nZVsxXSAtIHJlbGF0aXZlX2JfcGFkZGluZykKICAgICkgLyAyMAogICkKCiAgcmVsYXRpdmVfYl91cHBlciA8LSBtaW4oCiAgICAxLAogICAgY2VpbGluZygKICAgICAgMjAgKgogICAgICAgIChyZWxhdGl2ZV9iX3JhbmdlWzJdICsgcmVsYXRpdmVfYl9wYWRkaW5nKQogICAgKSAvIDIwCiAgKQoKICBpZiAocmVsYXRpdmVfYl9sb3dlciA+PSByZWxhdGl2ZV9iX3VwcGVyKSB7CiAgICByZWxhdGl2ZV9iX2xvd2VyIDwtIG1heCgKICAgICAgMCwKICAgICAgcmVsYXRpdmVfYl9sb3dlciAtIDAuMDUKICAgICkKICAgIHJlbGF0aXZlX2JfdXBwZXIgPC0gbWluKAogICAgICAxLAogICAgICByZWxhdGl2ZV9iX3VwcGVyICsgMC4wNQogICAgKQogIH0KCiAgcmVsYXRpdmVfcGFuZWxfYiA8LSBnZ3Bsb3QoCiAgICByZWxhdGl2ZV9wYW5lbF9iX2RhdGEsCiAgICBhZXMoCiAgICAgIHggPSBwYXJ0eV9uLAogICAgICB5ID0gZXN0aW1hdGUKICAgICkKICApICsKICAgIGdlb21faGxpbmUoCiAgICAgIHlpbnRlcmNlcHQgPSAwLjUsCiAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2xpbmUoCiAgICAgIGxpbmV3aWR0aCA9IDAuODAsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBnZW9tX2Vycm9yYmFyKAogICAgICBhZXMoCiAgICAgICAgeW1pbiA9IGNvbmZfbG93LAogICAgICAgIHltYXggPSBjb25mX2hpZ2gKICAgICAgKSwKICAgICAgd2lkdGggPSAwLjA3NSwKICAgICAgbGluZXdpZHRoID0gMC44MCwKICAgICAgY29sb3IgPSAiYmxhY2siCiAgICApICsKICAgIGdlb21fbGFiZWwoCiAgICAgIGFlcygKICAgICAgICBsYWJlbCA9IHZhbHVlX2xhYmVsCiAgICAgICksCiAgICAgIHNpemUgPSAzLjU1LAogICAgICBmYW1pbHkgPSByZWxhdGl2ZV9maWd1cmVfZm9udF9mYW1pbHksCiAgICAgIGxhYmVsLnNpemUgPSAwLAogICAgICBsYWJlbC5wYWRkaW5nID0gZ3JpZDo6dW5pdCgKICAgICAgICAwLjEyLAogICAgICAgICJsaW5lcyIKICAgICAgKSwKICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgIGNvbG9yID0gImJsYWNrIgogICAgKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgIGJyZWFrcyA9IDI6NSwKICAgICAgbGFiZWxzID0gcGFzdGUwKAogICAgICAgIDI6NSwKICAgICAgICAi6YG45oqe6IKiIgogICAgICApLAogICAgICBsaW1pdHMgPSBjKAogICAgICAgIDEuNzIsCiAgICAgICAgNS4yOAogICAgICApCiAgICApICsKICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgYnJlYWtzID0gc2VxKAogICAgICAgIHJlbGF0aXZlX2JfbG93ZXIsCiAgICAgICAgcmVsYXRpdmVfYl91cHBlciwKICAgICAgICBieSA9IDAuMDUKICAgICAgKSwKICAgICAgbGFiZWxzID0gbGFiZWxfcGVyY2VudCgKICAgICAgICBhY2N1cmFjeSA9IDEKICAgICAgKSwKICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKAogICAgICAgIG11bHQgPSBjKAogICAgICAgICAgMC4wNSwKICAgICAgICAgIDAuMDgKICAgICAgICApCiAgICAgICkKICAgICkgKwogICAgY29vcmRfY2FydGVzaWFuKAogICAgICB5bGltID0gYygKICAgICAgICByZWxhdGl2ZV9iX2xvd2VyLAogICAgICAgIHJlbGF0aXZlX2JfdXBwZXIKICAgICAgKQogICAgKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJC77ya55u45a++55qE44Gq5pS/5YWa5ZCN5omL44GM44GL44KK44Gu5q+U6YeNIiwKICAgICAgc3VidGl0bGUgPQogICAgICAgICLmlL/lhZrlkI3miYvjgYzjgYvjgorph43opoHluqYgw7fvvIjmlL/lhZrlkI3miYvjgYzjgYvjgorph43opoHluqbvvIvntYzmuIjmiYvjgYzjgYvjgorph43opoHluqbvvIkiLAogICAgICB4ID0gIuaUv+WFmumBuOaKnuiCouaVsCIsCiAgICAgIHkgPSAi55u45a++55qE44Gq5pS/5YWa5ZCN5omL44GM44GL44KK5q+U6YeNIgogICAgKSArCiAgICByZWxhdGl2ZV90aGVtZV9qYXBhbmVzZV9idyArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgICApCgogIHJlbGF0aXZlX3BhbmVsX2MgPC0gcmVsYXRpdmVfcGFuZWxfYiArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHBhc3RlMCgKICAgICAgICAiQu+8muebuOWvvueahOOBqiIsCiAgICAgICAgbGV2ZWxzKHJlbGF0aXZlX3BhbmVsX2FfZGF0YSRjdWVfZmFtaWx5KVsxXSwKICAgICAgICAi44Gu5q+U6YeNIgogICAgICApCiAgICApCgogIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAgPC0gKAogICAgcmVsYXRpdmVfcGFuZWxfYSB8CiAgICAgIHJlbGF0aXZlX3BhbmVsX2IKICApICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoCiAgICAgIHdpZHRocyA9IGMoCiAgICAgICAgMSwKICAgICAgICAxCiAgICAgICkKICAgICkKCiAgcHJpbnQoCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwCiAgKQoKICBzYXZlX3Bsb3QoCiAgICAiZmlnX3N0dWR5M19yZWxhdGl2ZV9jdWVfd2VpZ2h0X2pwX2J3LnBuZyIsCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwLAogICAgd2lkdGggPSAxMS4yLAogICAgaGVpZ2h0ID0gNS40LAogICAgZHBpID0gNDAwCiAgKQoKICBnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IGZpbGUucGF0aCgKICAgICAgb3V0cHV0X2RpciwKICAgICAgImZpZ19zdHVkeTNfcmVsYXRpdmVfY3VlX3dlaWdodF9qcF9idy5wZGYiCiAgICApLAogICAgcGxvdCA9IGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfanAsCiAgICB3aWR0aCA9IDExLjIsCiAgICBoZWlnaHQgPSA1LjQsCiAgICBkZXZpY2UgPSBnckRldmljZXM6OmNhaXJvX3BkZiwKICAgIGJnID0gIndoaXRlIgogICkKCiAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcCA8LSAoCiAgICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZCB8CiAgICAgIHJlbGF0aXZlX3BhbmVsX2MKICApICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoCiAgICAgIHdpZHRocyA9IGMoCiAgICAgICAgMSwKICAgICAgICAxCiAgICAgICkKICAgICkKCiAgcHJpbnQoCiAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwCiAgKQoKICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiA8LSBwYXN0ZTAoCiAgICAiZmlnX3N0dWR5IiwKICAgIHN0cmluZ3I6OnN0cl9leHRyYWN0KAogICAgICBzdHVkeV9sYWJlbCwKICAgICAgIlsxMjNdIgogICAgKSwKICAgICJfcmVsYXRpdmVfY3VlX3dlaWdodF9jaG9pY2Vfc2V0X2FkanVzdGVkX2pwX2J3IgogICkKCiAgc2F2ZV9wbG90KAogICAgcGFzdGUwKAogICAgICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiwKICAgICAgIi5wbmciCiAgICApLAogICAgZmlndXJlX3JlbGF0aXZlX3dlaWdodF9hZGp1c3RlZF9qcCwKICAgIHdpZHRoID0gMTEuMiwKICAgIGhlaWdodCA9IDUuNCwKICAgIGRwaSA9IDQwMAogICkKCiAgZ2dzYXZlKAogICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgIHBhc3RlMCgKICAgICAgICByZWxhdGl2ZV9hZGp1c3RlZF9maWd1cmVfc3R1YiwKICAgICAgICAiLnBkZiIKICAgICAgKQogICAgKSwKICAgIHBsb3QgPSBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwLAogICAgd2lkdGggPSAxMS4yLAogICAgaGVpZ2h0ID0gNS40LAogICAgZGV2aWNlID0gZ3JEZXZpY2VzOjpjYWlyb19wZGYsCiAgICBiZyA9ICJ3aGl0ZSIKICApCgogIHJlbGF0aXZlX2N1ZV9yZXN1bHRzIDwtIGxpc3QoCiAgICBwcmVwYXJlZCA9IHJlbGF0aXZlX2N1ZV9wcmVwYXJlZCwKICAgIG1hcmdpbmFsX21lYW5zID0KICAgICAgcmVsYXRpdmVfY3VlX29ic2VydmVkJG1hcmdpbmFsX21lYW5zLAogICAgYXR0cmlidXRlX2ltcG9ydGFuY2UgPQogICAgICByZWxhdGl2ZV9jdWVfb2JzZXJ2ZWQkYXR0cmlidXRlX2ltcG9ydGFuY2UsCiAgICBjdWVfaW1wb3J0YW5jZSA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgIG9ic2VydmVkX3Nsb3BlcyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9vYnNlcnZlZF9zbG9wZXMsCiAgICBjb25kaXRpb25fYm9vdHN0cmFwID0KICAgICAgcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9ib290c3RyYXAsCiAgICBzbG9wZV9ib290c3RyYXAgPQogICAgICByZWxhdGl2ZV9jdWVfc2xvcGVfYm9vdHN0cmFwLAogICAgY29uZGl0aW9uX2ludGVydmFscyA9CiAgICAgIHJlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzLAogICAgc2xvcGVfaW5mZXJlbmNlID0KICAgICAgcmVsYXRpdmVfY3VlX3Nsb3BlX2luZmVyZW5jZSwKICAgIHByaW1hcnlfcmVzdWx0ID0KICAgICAgcmVsYXRpdmVfY3VlX3ByaW1hcnlfcmVzdWx0LAogICAgcGxvdHMgPSBsaXN0KAogICAgICBhYnNvbHV0ZV9pbXBvcnRhbmNlID0gcmVsYXRpdmVfcGFuZWxfYSwKICAgICAgY2hvaWNlX3NldF9hZGp1c3RlZF9pbXBvcnRhbmNlID0KICAgICAgICByZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZCwKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0ID0gcmVsYXRpdmVfcGFuZWxfYiwKICAgICAgcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhbmVsX2MgPQogICAgICAgIHJlbGF0aXZlX3BhbmVsX2MsCiAgICAgIGNvbWJpbmVkID0gZmlndXJlX3JlbGF0aXZlX3dlaWdodF9qcCwKICAgICAgY29tYmluZWRfd2l0aF9jaG9pY2Vfc2V0X2FkanVzdG1lbnQgPQogICAgICAgIGZpZ3VyZV9yZWxhdGl2ZV93ZWlnaHRfYWRqdXN0ZWRfanAKICAgICkKICApCgogIHNhdmVSRFMoCiAgICByZWxhdGl2ZV9jdWVfcmVzdWx0cywKICAgIGZpbGUgPSBmaWxlLnBhdGgoCiAgICAgIG91dHB1dF9kaXIsCiAgICAgICJzdHVkeTNfcmVsYXRpdmVfY3VlX3Jlc3VsdHMucmRzIgogICAgKQogICkKCgogIHNhdmVSRFMoCiAgICBsaXN0KAogICAgICBzZXR0aW5ncyA9IGxpc3QoCiAgICAgICAgZGF0YV9maWxlID0gZGF0YV9maWxlLAogICAgICAgIHJlcXVpcmVfaW5pdGlhbF9jb25zZW50ID0KICAgICAgICAgIHJlcXVpcmVfaW5pdGlhbF9jb25zZW50LAogICAgICAgIHJlcXVpcmVfZmluYWxfY29uc2VudCA9CiAgICAgICAgICByZXF1aXJlX2ZpbmFsX2NvbnNlbnQsCiAgICAgICAgcmVxdWlyZV9hdHRlbnRpb25fY2hlY2sgPQogICAgICAgICAgcmVxdWlyZV9hdHRlbnRpb25fY2hlY2ssCiAgICAgICAgcmVxdWlyZV9tYW5pcHVsYXRpb25fY2hlY2sgPQogICAgICAgICAgcmVxdWlyZV9tYW5pcHVsYXRpb25fY2hlY2ssCiAgICAgICAgcmVxdWlyZV9hbGxfZml2ZV90YXNrcyA9CiAgICAgICAgICByZXF1aXJlX2FsbF9maXZlX3Rhc2tzLAogICAgICAgIHBhcnR5X3JlZmVyZW5jZSA9CiAgICAgICAgICBwYXJ0eV9yZWZlcmVuY2UsCiAgICAgICAgcGFydHlfbGV2ZWxzX3VzZSA9CiAgICAgICAgICBwYXJ0eV9sZXZlbHNfdXNlLAogICAgICAgIHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfQiA9CiAgICAgICAgICByZWxhdGl2ZV9jdWVfYm9vdHN0cmFwX0IsCiAgICAgICAgcmVsYXRpdmVfY3VlX2Jvb3RzdHJhcF9zZWVkID0KICAgICAgICAgIHJlbGF0aXZlX2N1ZV9ib290c3RyYXBfc2VlZAogICAgICApLAoKICAgICAgc2FtcGxlX2Zsb3cgPSBzYW1wbGVfZmxvdywKICAgICAgbl9ieV9wYXJ0eSA9IG5fYnlfcGFydHksCiAgICAgIHZhbGlkX2lkcyA9IHZhbGlkX2lkcywKCiAgICAgIGNvbmpvaW50X2FsbCA9IGNvbmpvaW50X2FsbCwKICAgICAgY29uam9pbnRfYWxsX20gPSBjb25qb2ludF9hbGxfbSwKICAgICAgY29uam9pbnRfYWxsX2NvdiA9IGNvbmpvaW50X2FsbF9jb3YsCgogICAgICBjb3Zhcl9pZCA9IGNvdmFyX2lkLAoKICAgICAgbW9kZWxzX2J5X3BhcnR5X25fbm9jb3YgPQogICAgICAgIG1vZGVsc19ieV9wYXJ0eV9uX25vY292LAoKICAgICAgbW9kZWxzX2J5X3BhcnR5X25fY292ID0KICAgICAgICBtb2RlbHNfYnlfcGFydHlfbl9jb3YsCgogICAgICBtX2ludGVyYWN0aW9uID0KICAgICAgICBtX2ludGVyYWN0aW9uLAoKICAgICAgbV9saW5lYXJfdHJlbmQgPQogICAgICAgIG1fbGluZWFyX3RyZW5kLAoKICAgICAgbW9kZWxzX2Nsb2dpdF9ub2NvdiA9CiAgICAgICAgbW9kZWxzX2Nsb2dpdF9ub2NvdiwKCiAgICAgIHBhcnR5X21hdGNoID0gbGlzdCgKICAgICAgICBkYXRhID0gY29uam9pbnRfbWF0Y2gsCiAgICAgICAgbW9kZWxzX2J5X24gPQogICAgICAgICAgbW9kZWxzX3BhcnR5X21hdGNoX2J5X24sCiAgICAgICAgaW50ZXJhY3Rpb25fbW9kZWwgPQogICAgICAgICAgbV9wYXJ0eV9tYXRjaF9pbnRlcmFjdGlvbgogICAgICApLAoKICAgICAgcmVsYXRpdmVfY3VlID0gcmVsYXRpdmVfY3VlX3Jlc3VsdHMsCgogICAgICBwbG90cyA9IGxpc3QoCiAgICAgICAgYW1jZV9jb3YgPQogICAgICAgICAgcF9hbWNlX2NvdiwKICAgICAgICBhbWNlX25vY292ID0KICAgICAgICAgIHBfYW1jZV9ub2NvdiwKICAgICAgICBpbnRlcmFjdGlvbiA9CiAgICAgICAgICBwX2ludGVyYWN0aW9uLAogICAgICAgIGxpbmVhcl90cmVuZCA9CiAgICAgICAgICBwX2xpbmVhcl90cmVuZCwKICAgICAgICBoZWF0bWFwID0KICAgICAgICAgIHBfaGVhdF9hbWNlLAogICAgICAgIGNsb2dpdF9vZGRzX3JhdGlvID0KICAgICAgICAgIHBfY2xvZ2l0X29yLAogICAgICAgIHBhcnR5X21hdGNoID0KICAgICAgICAgIHBfcGFydHlfbWF0Y2gsCiAgICAgICAgcmVsYXRpdmVfY3VlX3dlaWdodCA9CiAgICAgICAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2pwLAogICAgICAgIHJlbGF0aXZlX2N1ZV93ZWlnaHRfY2hvaWNlX3NldF9hZGp1c3RlZCA9CiAgICAgICAgICBmaWd1cmVfcmVsYXRpdmVfd2VpZ2h0X2FkanVzdGVkX2pwCiAgICAgICkKICAgICksCiAgICBmaWxlID0gZmlsZS5wYXRoKAogICAgICBvdXRwdXRfZGlyLAogICAgICAic3R1ZHkzX2FuYWx5c2lzX29iamVjdHMucmRzIgogICAgKQogICkKCiAgY2FwdHVyZS5vdXRwdXQoCiAgICBzZXNzaW9uSW5mbygpLAogICAgZmlsZSA9IGZpbGUucGF0aCgKICAgICAgb3V0cHV0X2RpciwKICAgICAgInNlc3Npb25JbmZvLnR4dCIKICAgICkKICApCgogIGNhdCgKICAgICJcblN0dWR5IDPjga7liIbmnpDjgrPjg7zjg4njgYzmnIDlvozjgb7jgaflrozkuobjgZfjgb7jgZfjgZ/jgIJcbiIsCiAgICAi5Ye65Yqb5YWIOiAiLAogICAgbm9ybWFsaXplUGF0aChvdXRwdXRfZGlyKSwKICAgICJcbiIsCiAgICBzZXAgPSAiIgogICkKCiAgZW52aXJvbm1lbnQoKQp9KQpgYGAKCiMjIEEuNSDoo5zpgbrjgavplqLjgZnjgovlkITnqK7jga7lho3nj77jgrPjg7zjg4kKCmBgYHtyIGE1LXN1cHBsZW1lbnQtY29kZSwgZXZhbD1wYXJhbXMkcnVuX2FuYWx5c2lzLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQoKIyDoo5zpgbrlhbHpgJrjgrPjg7zjg4kKdW5pZmllZF9vdXRwdXRfZGlyIDwtIGZpbGUucGF0aCgKICB1bmlmaWVkX2NvbmZpZyRvdXRwdXRfcm9vdCwKICAiX3dvcmtpbmciLAogICJjcm9zc19zdHVkeSIKKQpkaXIuY3JlYXRlKHVuaWZpZWRfb3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCgpzYXZlX3Bsb3RfYm90aCA8LSBmdW5jdGlvbihmaWxlbmFtZV9zdHViLCBwbG90LCB3aWR0aCwgaGVpZ2h0LCBkcGkgPSA0MDApIHsKICBwbmdfZmlsZSA8LSBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCBwYXN0ZTAoZmlsZW5hbWVfc3R1YiwgIi5wbmciKSkKICBwZGZfZmlsZSA8LSBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCBwYXN0ZTAoZmlsZW5hbWVfc3R1YiwgIi5wZGYiKSkKICAKICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IHBuZ19maWxlLAogICAgcGxvdCA9IHBsb3QsCiAgICB3aWR0aCA9IHdpZHRoLAogICAgaGVpZ2h0ID0gaGVpZ2h0LAogICAgZHBpID0gZHBpLAogICAgYmcgPSAid2hpdGUiCiAgKQogIAogIGdncGxvdDI6Omdnc2F2ZSgKICAgIGZpbGVuYW1lID0gcGRmX2ZpbGUsCiAgICBwbG90ID0gcGxvdCwKICAgIHdpZHRoID0gd2lkdGgsCiAgICBoZWlnaHQgPSBoZWlnaHQsCiAgICBkZXZpY2UgPSBnckRldmljZXM6OmNhaXJvX3BkZiwKICAgIGJnID0gIndoaXRlIgogICkKICAKICBpbnZpc2libGUoYyhwbmcgPSBwbmdfZmlsZSwgcGRmID0gcGRmX2ZpbGUpKQp9Cgp3cml0ZV9jc3ZfdW5pZmllZCA8LSBmdW5jdGlvbih4LCBmaWxlbmFtZSkgewogIHJlYWRyOjp3cml0ZV9jc3YoCiAgICB4LAogICAgZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgZmlsZW5hbWUpLAogICAgbmEgPSAiIgogICkKfQoKc2FmZV9maWxlbmFtZSA8LSBmdW5jdGlvbih4KSB7CiAgeCA8LSBpY29udihhcy5jaGFyYWN0ZXIoeCksIGZyb20gPSAiIiwgdG8gPSAiQVNDSUkvL1RSQU5TTElUIikKICB4W2lzLm5hKHgpIHwgeCA9PSAiIl0gPC0gImdyb3VwIgogIHggPC0gdG9sb3dlcih4KQogIHggPC0gZ3N1YigiW15hLXowLTldKyIsICJfIiwgeCkKICB4IDwtIGdzdWIoIl5fK3xfKyQiLCAiIiwgeCkKICBpZmVsc2UoeCA9PSAiIiwgImdyb3VwIiwgeCkKfQoKdGlkeV9maXhlc3RfdW5pZmllZCA8LSBmdW5jdGlvbihtb2RlbCkgewogIGN0IDwtIGFzLmRhdGEuZnJhbWUoZml4ZXN0Ojpjb2VmdGFibGUobW9kZWwpKQogIGN0JHRlcm0gPC0gcm93bmFtZXMoY3QpCiAgCiAgZXN0aW1hdGVfY29sIDwtIGludGVyc2VjdChjKCJFc3RpbWF0ZSIsICJlc3RpbWF0ZSIpLCBuYW1lcyhjdCkpWzFdCiAgc2VfY29sIDwtIGludGVyc2VjdChjKCJTdGQuIEVycm9yIiwgIlN0ZC4gZXJyb3IiLCAic3RkLmVycm9yIiksIG5hbWVzKGN0KSlbMV0KICBzdGF0aXN0aWNfY29sIDwtIGludGVyc2VjdChjKCJ0IHZhbHVlIiwgInogdmFsdWUiLCAic3RhdGlzdGljIiksIG5hbWVzKGN0KSlbMV0KICBwX2NvbCA8LSBpbnRlcnNlY3QoYygiUHIoPnx0fCkiLCAiUHIoPnx6fCkiLCAicC52YWx1ZSIpLCBuYW1lcyhjdCkpWzFdCiAgCiAgaWYgKAogICAgaXMubmEoZXN0aW1hdGVfY29sKSB8fAogICAgaXMubmEoc2VfY29sKSB8fAogICAgaXMubmEoc3RhdGlzdGljX2NvbCkgfHwKICAgIGlzLm5hKHBfY29sKQogICkgewogICAgc3RvcCgiQ2hlY2sgZGF0YSIpCiAgfQogIAogIHRpYmJsZTo6YXNfdGliYmxlKGN0KSAlPiUKICAgIGRwbHlyOjp0cmFuc211dGUoCiAgICAgIHRlcm0gPSB0ZXJtLAogICAgICBlc3RpbWF0ZSA9IC5kYXRhW1tlc3RpbWF0ZV9jb2xdXSwKICAgICAgc3RkLmVycm9yID0gLmRhdGFbW3NlX2NvbF1dLAogICAgICBzdGF0aXN0aWMgPSAuZGF0YVtbc3RhdGlzdGljX2NvbF1dLAogICAgICBwLnZhbHVlID0gLmRhdGFbW3BfY29sXV0sCiAgICAgIGNvbmYubG93ID0gZXN0aW1hdGUgLSAxLjk2ICogc3RkLmVycm9yLAogICAgICBjb25mLmhpZ2ggPSBlc3RpbWF0ZSArIDEuOTYgKiBzdGQuZXJyb3IKICAgICkKfQoKc3R1ZHlfc3BlY3MgPC0gbGlzdCgKICBzdHVkeTEgPSBsaXN0KAogICAgc3R1ZHlfaWQgPSAic3R1ZHkxIiwKICAgIHN0dWR5X2xhYmVsID0gIlN0dWR5IDHvvIgyMDIz5bm077yJIiwKICAgIGNvbmRpdGlvbl9sYWJlbCA9ICLmlL/lhZrmlbAiLAogICAgZW52ID0gc3R1ZHkxX2VudgogICksCiAgc3R1ZHkyID0gbGlzdCgKICAgIHN0dWR5X2lkID0gInN0dWR5MiIsCiAgICBzdHVkeV9sYWJlbCA9ICJTdHVkeSAy77yIMjAyNuW5tO+8iSIsCiAgICBjb25kaXRpb25fbGFiZWwgPSAi5pS/5YWa5pWwIiwKICAgIGVudiA9IHN0dWR5Ml9lbnYKICApLAogIHN0dWR5MyA9IGxpc3QoCiAgICBzdHVkeV9pZCA9ICJzdHVkeTMiLAogICAgc3R1ZHlfbGFiZWwgPSAiU3R1ZHkgM++8iDIwMjblubTvvIkiLAogICAgY29uZGl0aW9uX2xhYmVsID0gIumBuOaKnuiCouaVsCIsCiAgICBlbnYgPSBzdHVkeTNfZW52CiAgKQopCgpleGNsdWRlZF9zdXBwb3J0X2NhdGVnb3JpZXMgPC0gYygKICAi44Gd44Gu5LuWIiwKICAi44KP44GL44KJ44Gq44GEIiwKICAi562U44GI44Gq44GEIiwKICAi562U44GI44Gf44GP44Gq44GEIiwKICAi5qyg5pCN44O754Sh5Zue562UIgopCgoKIyDoo5zpgbpD6Zai6YCj44Kz44O844OJCmJhbGFuY2VfdmFyaWFibGVfbGFiZWxzIDwtIGMoCiAgZmVtYWxlX2ltcCA9ICLlpbPmgKciLAogIGZlbWFsZV9taXNzID0gIuaAp+WIpe+8muasoOaQjSIsCiAgYWdlX2ltcCA9ICLlubTpvaIiLAogIGFnZV9taXNzID0gIuW5tOm9ou+8muasoOaQjSIsCiAgY29sbGVnZV9ncmFkX2ltcCA9ICI05bm05Yi25aSn5a2m5Lul5LiKIiwKICBjb2xsZWdlX2dyYWRfbWlzcyA9ICLlrabmrbTvvJrmrKDmkI0iLAogIGluY29tZV9ncm9zc19sb2dfaW1wID0gIuS4luW4r+W5tOWPju+8iOWvvuaVsO+8iSIsCiAgaW5jb21lX2dyb3NzX2xvZ19taXNzID0gIuS4luW4r+W5tOWPju+8muasoOaQjSIsCiAgc2VsZl9pZGVvbG9neV9pbXAgPSAi5bem5Y+z6Ieq5bex5L2N572u44Gl44GRIiwKICBzZWxmX2lkZW9sb2d5X21pc3MgPSAi5bem5Y+z6Ieq5bex5L2N572u44Gl44GR77ya5qyg5pCNIgopCgptYWtlX2JhbGFuY2VfZGVzaWduIDwtIGZ1bmN0aW9uKHN0dWR5X3NwZWMpIHsKICBlbnYgPC0gc3R1ZHlfc3BlYyRlbnYKICAKICBhc3NpZ25tZW50IDwtIGVudiRjb25qb2ludF9hbGwgJT4lCiAgICBkcGx5cjo6ZGlzdGluY3QoSUQsIHBhcnR5X24pICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoSUQpLAogICAgICBwYXJ0eV9uID0gYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIocGFydHlfbikpCiAgICApCiAgCiAgcmVzcG9uZGVudCA8LSBlbnYkY292YXJfaWQgJT4lCiAgICBkcGx5cjo6bXV0YXRlKElEID0gYXMuY2hhcmFjdGVyKElEKSkKICAKICBkYXQgPC0gYXNzaWdubWVudCAlPiUKICAgIGRwbHlyOjpsZWZ0X2pvaW4ocmVzcG9uZGVudCwgYnkgPSAiSUQiKQogIAogIG51bWVyaWNfY2FuZGlkYXRlcyA8LSBjKAogICAgImZlbWFsZV9pbXAiLAogICAgImZlbWFsZV9taXNzIiwKICAgICJhZ2VfaW1wIiwKICAgICJhZ2VfbWlzcyIsCiAgICAiY29sbGVnZV9ncmFkX2ltcCIsCiAgICAiY29sbGVnZV9ncmFkX21pc3MiLAogICAgImluY29tZV9ncm9zc19sb2dfaW1wIiwKICAgICJpbmNvbWVfZ3Jvc3NfbG9nX21pc3MiLAogICAgInNlbGZfaWRlb2xvZ3lfaW1wIiwKICAgICJzZWxmX2lkZW9sb2d5X21pc3MiCiAgKQogIAogIGZhY3Rvcl9jYW5kaWRhdGVzIDwtIGMoCiAgICAicGFydHlfc3VwcG9ydF9mIiwKICAgICJyZWdpb24iCiAgKQogIAogIG51bWVyaWNfdXNlIDwtIGludGVyc2VjdChudW1lcmljX2NhbmRpZGF0ZXMsIG5hbWVzKGRhdCkpCiAgZmFjdG9yX3VzZSA8LSBpbnRlcnNlY3QoZmFjdG9yX2NhbmRpZGF0ZXMsIG5hbWVzKGRhdCkpCiAgCiAgZGVzaWduX3NvdXJjZSA8LSBkYXQgJT4lCiAgICBkcGx5cjo6c2VsZWN0KGRwbHlyOjphbGxfb2YoYyhudW1lcmljX3VzZSwgZmFjdG9yX3VzZSkpKQogIAogIGlmIChsZW5ndGgoZmFjdG9yX3VzZSkgPiAwKSB7CiAgICBkZXNpZ25fc291cmNlIDwtIGRlc2lnbl9zb3VyY2UgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgZHBseXI6OmFjcm9zcygKICAgICAgICAgIGRwbHlyOjphbGxfb2YoZmFjdG9yX3VzZSksCiAgICAgICAgICB+IGZvcmNhdHM6OmZjdF9uYV92YWx1ZV90b19sZXZlbChhcy5mYWN0b3IoLngpLCBsZXZlbCA9ICLmrKDmkI3jg7vnhKHlm57nrZQiKQogICAgICAgICkKICAgICAgKQogIH0KICAKICBtbSA8LSBzdGF0czo6bW9kZWwubWF0cml4KAogICAgc3RhdHM6OmFzLmZvcm11bGEoCiAgICAgIHBhc3RlMCgKICAgICAgICAifiAwICsgIiwKICAgICAgICBwYXN0ZShuYW1lcyhkZXNpZ25fc291cmNlKSwgY29sbGFwc2UgPSAiICsgIikKICAgICAgKQogICAgKSwKICAgIGRhdGEgPSBkZXNpZ25fc291cmNlCiAgKQogIAogIG1tIDwtIGFzLmRhdGEuZnJhbWUobW0sIGNoZWNrLm5hbWVzID0gRkFMU0UpCiAgCiAga2VlcCA8LSB2YXBwbHkoCiAgICBtbSwKICAgIGZ1bmN0aW9uKHgpIHsKICAgICAgeCA8LSBhcy5udW1lcmljKHgpCiAgICAgIGlzLmZpbml0ZShzdGF0czo6c2QoeCwgbmEucm0gPSBUUlVFKSkgJiYgc3RhdHM6OnNkKHgsIG5hLnJtID0gVFJVRSkgPiAwCiAgICB9LAogICAgbG9naWNhbCgxKQogICkKICAKICBtbSA8LSBtbVssIGtlZXAsIGRyb3AgPSBGQUxTRV0KICAKICBtbSA8LSBtbSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIElEID0gZGF0JElELAogICAgICBwYXJ0eV9uID0gZGF0JHBhcnR5X24sCiAgICAgIC5iZWZvcmUgPSAxCiAgICApCiAgCiAgbG9uZyA8LSBtbSAlPiUKICAgIHRpZHlyOjpwaXZvdF9sb25nZXIoCiAgICAgIGNvbHMgPSAtYyhJRCwgcGFydHlfbiksCiAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwKICAgICAgdmFsdWVzX3RvID0gInZhbHVlIgogICAgKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIGxhYmVsID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgICB2YXJpYWJsZSAlaW4lIG5hbWVzKGJhbGFuY2VfdmFyaWFibGVfbGFiZWxzKSB+CiAgICAgICAgICB1bm5hbWUoYmFsYW5jZV92YXJpYWJsZV9sYWJlbHNbdmFyaWFibGVdKSwKICAgICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHZhcmlhYmxlLCAiXnBhcnR5X3N1cHBvcnRfZiIpIH4KICAgICAgICAgIHBhc3RlMCgKICAgICAgICAgICAgIuaUr+aMgeaUv+WFmu+8miIsCiAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9yZW1vdmUodmFyaWFibGUsICJecGFydHlfc3VwcG9ydF9mIikKICAgICAgICAgICksCiAgICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdCh2YXJpYWJsZSwgIl5yZWdpb24iKSB+CiAgICAgICAgICBwYXN0ZTAoCiAgICAgICAgICAgICLlnLDln5/vvJoiLAogICAgICAgICAgICBzdHJpbmdyOjpzdHJfcmVtb3ZlKHZhcmlhYmxlLCAiXnJlZ2lvbiIpCiAgICAgICAgICApLAogICAgICAgIFRSVUUgfiB2YXJpYWJsZQogICAgICApLAogICAgICBzdHVkeV9pZCA9IHN0dWR5X3NwZWMkc3R1ZHlfaWQsCiAgICAgIHN0dWR5X2xhYmVsID0gc3R1ZHlfc3BlYyRzdHVkeV9sYWJlbAogICAgKQogIAogIGxpc3QoCiAgICByZXNwb25kZW50ID0gZGF0LAogICAgbWF0cml4ID0gbW0sCiAgICBsb25nID0gbG9uZywKICAgIG51bWVyaWNfdXNlID0gbnVtZXJpY191c2UsCiAgICBmYWN0b3JfdXNlID0gZmFjdG9yX3VzZQogICkKfQoKcGFpcndpc2Vfc21kX211bHRpYXJtIDwtIGZ1bmN0aW9uKGJhbGFuY2VfbG9uZykgewogIGdyb3VwcyA8LSBzb3J0KHVuaXF1ZShiYWxhbmNlX2xvbmckcGFydHlfbikpCiAgcGFpcnMgPC0gdXRpbHM6OmNvbWJuKGdyb3VwcywgMiwgc2ltcGxpZnkgPSBGQUxTRSkKCiAgcHVycnI6Om1hcF9kZnIoCiAgICBwYWlycywKICAgIGZ1bmN0aW9uKHBhaXJfdmFsdWUpIHsKICAgICAgYSA8LSBwYWlyX3ZhbHVlWzFdCiAgICAgIGIgPC0gcGFpcl92YWx1ZVsyXQoKICAgICAgd2lkZSA8LSBiYWxhbmNlX2xvbmcgJT4lCiAgICAgICAgZHBseXI6OmZpbHRlcihwYXJ0eV9uICVpbiUgYyhhLCBiKSkgJT4lCiAgICAgICAgZHBseXI6Omdyb3VwX2J5KHZhcmlhYmxlLCBsYWJlbCwgcGFydHlfbikgJT4lCiAgICAgICAgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgICAgIG1lYW4gPSBtZWFuKHZhbHVlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgc2QgPSBzdGF0czo6c2QodmFsdWUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICBuID0gc3VtKCFpcy5uYSh2YWx1ZSkpLAogICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICAgICkgJT4lCiAgICAgICAgdGlkeXI6OnBpdm90X3dpZGVyKAogICAgICAgICAgbmFtZXNfZnJvbSA9IHBhcnR5X24sCiAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGMobWVhbiwgc2QsIG4pLAogICAgICAgICAgbmFtZXNfc2VwID0gIl8iCiAgICAgICAgKQoKICAgICAgd2lkZSAlPiUKICAgICAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICAgICAgdmFyaWFibGUgPSB2YXJpYWJsZSwKICAgICAgICAgIGxhYmVsID0gbGFiZWwsCiAgICAgICAgICBjb25kaXRpb25fYSA9IGEsCiAgICAgICAgICBjb25kaXRpb25fYiA9IGIsCiAgICAgICAgICBjb21wYXJpc29uID0gcGFzdGUwKGEsICIgdnMgIiwgYiksCiAgICAgICAgICBtZWFuX2EgPSAuZGF0YVtbcGFzdGUwKCJtZWFuXyIsIGEpXV0sCiAgICAgICAgICBtZWFuX2IgPSAuZGF0YVtbcGFzdGUwKCJtZWFuXyIsIGIpXV0sCiAgICAgICAgICBzZF9hID0gLmRhdGFbW3Bhc3RlMCgic2RfIiwgYSldXSwKICAgICAgICAgIHNkX2IgPSAuZGF0YVtbcGFzdGUwKCJzZF8iLCBiKV1dLAogICAgICAgICAgbl9hID0gLmRhdGFbW3Bhc3RlMCgibl8iLCBhKV1dLAogICAgICAgICAgbl9iID0gLmRhdGFbW3Bhc3RlMCgibl8iLCBiKV1dLAogICAgICAgICAgcG9vbGVkX3NkID0gc3FydCgoc2RfYV4yICsgc2RfYl4yKSAvIDIpLAogICAgICAgICAgc21kID0gZHBseXI6OmlmX2Vsc2UoCiAgICAgICAgICAgIGlzLmZpbml0ZShwb29sZWRfc2QpICYgcG9vbGVkX3NkID4gMCwKICAgICAgICAgICAgKG1lYW5fYSAtIG1lYW5fYikgLyBwb29sZWRfc2QsCiAgICAgICAgICAgIE5BX3JlYWxfCiAgICAgICAgICApLAogICAgICAgICAgYWJzX3NtZCA9IGFicyhzbWQpCiAgICAgICAgKQogICAgfQogICkKfQoKb21uaWJ1c19iYWxhbmNlX3Rlc3QgPC0gZnVuY3Rpb24oYmFsYW5jZV9sb25nKSB7CiAgYmFsYW5jZV9sb25nICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHZhcmlhYmxlLCBsYWJlbCkgJT4lCiAgICBkcGx5cjo6Z3JvdXBfbW9kaWZ5KAogICAgICB+IHsKICAgICAgICBkYXQgPC0gLnggJT4lCiAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGlzLmZpbml0ZSh2YWx1ZSksICFpcy5uYShwYXJ0eV9uKSkKICAgICAgICAKICAgICAgICBwX3ZhbHVlIDwtIHRyeUNhdGNoKAogICAgICAgICAgewogICAgICAgICAgICBtb2RlbCA8LSBzdGF0czo6bG0odmFsdWUgfiBmYWN0b3IocGFydHlfbiksIGRhdGEgPSBkYXQpCiAgICAgICAgICAgIGFzLm51bWVyaWMoc3RhdHM6OmFub3ZhKG1vZGVsKVsxLCAiUHIoPkYpIl0pCiAgICAgICAgICB9LAogICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSBOQV9yZWFsXwogICAgICAgICkKICAgICAgICAKICAgICAgICB0aWJibGU6OnRpYmJsZShwX3ZhbHVlID0gcF92YWx1ZSkKICAgICAgfQogICAgKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKHBfaG9sbSA9IHN0YXRzOjpwLmFkanVzdChwX3ZhbHVlLCBtZXRob2QgPSAiaG9sbSIpKQp9CgptYWtlX2JhbGFuY2Vfb3V0cHV0cyA8LSBmdW5jdGlvbihzdHVkeV9zcGVjKSB7CiAgZGVzaWduIDwtIG1ha2VfYmFsYW5jZV9kZXNpZ24oc3R1ZHlfc3BlYykKICBsb25nIDwtIGRlc2lnbiRsb25nCiAgcGFpcndpc2UgPC0gcGFpcndpc2Vfc21kX211bHRpYXJtKGxvbmcpCiAgb21uaWJ1cyA8LSBvbW5pYnVzX2JhbGFuY2VfdGVzdChsb25nKQogIAogIG1heF9zbWQgPC0gcGFpcndpc2UgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkodmFyaWFibGUsIGxhYmVsKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIG1heF9hYnNfc21kID0gZHBseXI6OmlmX2Vsc2UoCiAgICAgICAgYWxsKGlzLm5hKGFic19zbWQpKSwKICAgICAgICBOQV9yZWFsXywKICAgICAgICBtYXgoYWJzX3NtZCwgbmEucm0gPSBUUlVFKQogICAgICApLAogICAgICBtZWFuX2Fic19zbWQgPSBkcGx5cjo6aWZfZWxzZSgKICAgICAgICBhbGwoaXMubmEoYWJzX3NtZCkpLAogICAgICAgIE5BX3JlYWxfLAogICAgICAgIG1lYW4oYWJzX3NtZCwgbmEucm0gPSBUUlVFKQogICAgICApLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApCiAgCiAgZ3JvdXBfc3VtbWFyeSA8LSBsb25nICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHZhcmlhYmxlLCBsYWJlbCwgcGFydHlfbikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICBtZWFuID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKSwKICAgICAgc2QgPSBzdGF0czo6c2QodmFsdWUsIG5hLnJtID0gVFJVRSksCiAgICAgIG4gPSBzdW0oIWlzLm5hKHZhbHVlKSksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkgJT4lCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIoCiAgICAgIG5hbWVzX2Zyb20gPSBwYXJ0eV9uLAogICAgICB2YWx1ZXNfZnJvbSA9IGMobWVhbiwgc2QsIG4pLAogICAgICBuYW1lc19nbHVlID0gInsudmFsdWV9X2NvbmRpdGlvbl97cGFydHlfbn0iCiAgICApICU+JQogICAgZHBseXI6OmxlZnRfam9pbihtYXhfc21kLCBieSA9IGMoInZhcmlhYmxlIiwgImxhYmVsIikpICU+JQogICAgZHBseXI6OmxlZnRfam9pbihvbW5pYnVzLCBieSA9IGMoInZhcmlhYmxlIiwgImxhYmVsIikpICU+JQogICAgZHBseXI6OmFycmFuZ2UoZHBseXI6OmRlc2MobWF4X2Fic19zbWQpKQogIAogIHdyaXRlX2Nzdl91bmlmaWVkKAogICAgcGFpcndpc2UsCiAgICBwYXN0ZTAoc3R1ZHlfc3BlYyRzdHVkeV9pZCwgIl9hc3NpZ25tZW50X2JhbGFuY2VfcGFpcndpc2Vfc21kLmNzdiIpCiAgKQogIHdyaXRlX2Nzdl91bmlmaWVkKAogICAgZ3JvdXBfc3VtbWFyeSwKICAgIHBhc3RlMChzdHVkeV9zcGVjJHN0dWR5X2lkLCAiX2Fzc2lnbm1lbnRfYmFsYW5jZV9zdW1tYXJ5LmNzdiIpCiAgKQogIAogIGxvdmVfZGYgPC0gcGFpcndpc2UgJT4lCiAgICBkcGx5cjo6bGVmdF9qb2luKG1heF9zbWQsIGJ5ID0gYygidmFyaWFibGUiLCAibGFiZWwiKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBsYWJlbF9vcmRlcmVkID0gc3RhdHM6OnJlb3JkZXIobGFiZWwsIG1heF9hYnNfc21kKQogICAgKQogIAogIHBfbG92ZSA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBsb3ZlX2RmLAogICAgZ2dwbG90Mjo6YWVzKAogICAgICB4ID0gYWJzX3NtZCwKICAgICAgeSA9IGxhYmVsX29yZGVyZWQKICAgICkKICApICsKICAgIGdncGxvdDI6Omdlb21fdmxpbmUoCiAgICAgIHhpbnRlcmNlcHQgPSAwLjEwLAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICBsaW5ld2lkdGggPSAwLjU1CiAgICApICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgIGFscGhhID0gMC4zMCwKICAgICAgc2l6ZSA9IDEuNCwKICAgICAgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9qaXR0ZXIoaGVpZ2h0ID0gMC4xMCwgd2lkdGggPSAwKQogICAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgICBkYXRhID0gbWF4X3NtZCAlPiUKICAgICAgICBkcGx5cjo6bXV0YXRlKGxhYmVsX29yZGVyZWQgPSBzdGF0czo6cmVvcmRlcihsYWJlbCwgbWF4X2Fic19zbWQpKSwKICAgICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBtYXhfYWJzX3NtZCwKICAgICAgICB5ID0gbGFiZWxfb3JkZXJlZAogICAgICApLAogICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgICBzaGFwZSA9IDIxLAogICAgICBmaWxsID0gIndoaXRlIiwKICAgICAgc2l6ZSA9IDIuNSwKICAgICAgc3Ryb2tlID0gMC44CiAgICApICsKICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cygKICAgICAgYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSA2KSwKICAgICAgZXhwYW5kID0gZ2dwbG90Mjo6ZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMDUpKQogICAgKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICB4ID0gIuadoeS7tumWk+OBrue1tuWvvuaomea6luWMluW5s+Wdh+W3ru+8iHxTTUR877yJIiwKICAgICAgeSA9IE5VTEwsCiAgICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAgIHN0dWR5X3NwZWMkc3R1ZHlfbGFiZWwsCiAgICAgICAgIu+8muWQhOeCueOBr+adoeS7tuODmuOCouOAgeeZveaKnOOBjeeCueOBr+acgOWkp+e1tuWvvlNNRCIKICAgICAgKSwKICAgICAgY2FwdGlvbiA9ICLnoLTnt5rjga8gfFNNRHwgPSAwLjEw44CC5aSa576k54Sh5L2c54K65Ymy5LuY44Gu44Gf44KB44CBMuODuzPjg7s044O7NeadoeS7tuOBruWFqDbjg5rjgqLjgpLmr5TovIPjgIIiCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDExKSArCiAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICAgICkKICAKICBzYXZlX3Bsb3RfYm90aCgKICAgIHBhc3RlMChzdHVkeV9zcGVjJHN0dWR5X2lkLCAiX2Fzc2lnbm1lbnRfYmFsYW5jZV9sb3ZlX3Bsb3QiKSwKICAgIHBfbG92ZSwKICAgIHdpZHRoID0gOS4yLAogICAgaGVpZ2h0ID0gbWF4KDYuNSwgMC4yMyAqIGRwbHlyOjpuX2Rpc3RpbmN0KGxvdmVfZGYkbGFiZWwpICsgMi41KQogICkKICAKICBzdGFuZGFyZGl6ZWRfbWVhbnMgPC0gbG9uZyAlPiUKICAgIGRwbHlyOjpncm91cF9ieSh2YXJpYWJsZSwgbGFiZWwpICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgb3ZlcmFsbF9tZWFuID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKSwKICAgICAgb3ZlcmFsbF9zZCA9IHN0YXRzOjpzZCh2YWx1ZSwgbmEucm0gPSBUUlVFKSwKICAgICAgdmFsdWVfeiA9IGRwbHlyOjppZl9lbHNlKAogICAgICAgIGlzLmZpbml0ZShvdmVyYWxsX3NkKSAmIG92ZXJhbGxfc2QgPiAwLAogICAgICAgICh2YWx1ZSAtIG92ZXJhbGxfbWVhbikgLyBvdmVyYWxsX3NkLAogICAgICAgIE5BX3JlYWxfCiAgICAgICkKICAgICkgJT4lCiAgICBkcGx5cjo6dW5ncm91cCgpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHZhcmlhYmxlLCBsYWJlbCwgcGFydHlfbikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICBtZWFuX3ogPSBtZWFuKHZhbHVlX3osIG5hLnJtID0gVFJVRSksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkKICAKICBncm91cHMgPC0gc29ydCh1bmlxdWUoc3RhbmRhcmRpemVkX21lYW5zJHBhcnR5X24pKQogIGRpYWdvbmFsX2RmIDwtIHB1cnJyOjptYXBfZGZyKAogICAgdXRpbHM6OmNvbWJuKGdyb3VwcywgMiwgc2ltcGxpZnkgPSBGQUxTRSksCiAgICBmdW5jdGlvbihwYWlyX3ZhbHVlKSB7CiAgICAgIGEgPC0gcGFpcl92YWx1ZVsxXQogICAgICBiIDwtIHBhaXJfdmFsdWVbMl0KICAgICAgCiAgICAgIHN0YW5kYXJkaXplZF9tZWFucyAlPiUKICAgICAgICBkcGx5cjo6ZmlsdGVyKHBhcnR5X24gJWluJSBjKGEsIGIpKSAlPiUKICAgICAgICB0aWR5cjo6cGl2b3Rfd2lkZXIoCiAgICAgICAgICBuYW1lc19mcm9tID0gcGFydHlfbiwKICAgICAgICAgIHZhbHVlc19mcm9tID0gbWVhbl96LAogICAgICAgICAgbmFtZXNfcHJlZml4ID0gImNvbmRpdGlvbl8iCiAgICAgICAgKSAlPiUKICAgICAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgICAgY29uZGl0aW9uX2EgPSBhLAogICAgICAgICAgY29uZGl0aW9uX2IgPSBiLAogICAgICAgICAgY29tcGFyaXNvbiA9IHBhc3RlMChhLCAiIHZzICIsIGIpLAogICAgICAgICAgeF9tZWFuID0gLmRhdGFbW3Bhc3RlMCgiY29uZGl0aW9uXyIsIGEpXV0sCiAgICAgICAgICB5X21lYW4gPSAuZGF0YVtbcGFzdGUwKCJjb25kaXRpb25fIiwgYildXSwKICAgICAgICAgIGRpYWdvbmFsX2RldmlhdGlvbiA9IHlfbWVhbiAtIHhfbWVhbiwKICAgICAgICAgIGFic19kaWFnb25hbF9kZXZpYXRpb24gPSBhYnMoZGlhZ29uYWxfZGV2aWF0aW9uKQogICAgICAgICkKICAgIH0KICApCiAgCiAgdG9wX2xhYmVscyA8LSBkaWFnb25hbF9kZiAlPiUKICAgIGRwbHlyOjpncm91cF9ieShjb21wYXJpc29uKSAlPiUKICAgIGRwbHlyOjpzbGljZV9tYXgoCiAgICAgIG9yZGVyX2J5ID0gYWJzX2RpYWdvbmFsX2RldmlhdGlvbiwKICAgICAgbiA9IDMsCiAgICAgIHdpdGhfdGllcyA9IEZBTFNFCiAgICApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQogIAogIGF4aXNfbGltaXQgPC0gbWF4KAogICAgYWJzKGMoZGlhZ29uYWxfZGYkeF9tZWFuLCBkaWFnb25hbF9kZiR5X21lYW4pKSwKICAgIG5hLnJtID0gVFJVRQogICkKICBheGlzX2xpbWl0IDwtIG1heCgwLjEwLCBheGlzX2xpbWl0ICogMS4xNSkKICAKICBwX2RpYWdvbmFsIDwtIGdncGxvdDI6OmdncGxvdCgKICAgIGRpYWdvbmFsX2RmLAogICAgZ2dwbG90Mjo6YWVzKHggPSB4X21lYW4sIHkgPSB5X21lYW4pCiAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2FibGluZSgKICAgICAgaW50ZXJjZXB0ID0gMCwKICAgICAgc2xvcGUgPSAxLAogICAgICBsaW5ld2lkdGggPSAwLjYwLAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgICApICsKICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMjUpICsKICAgIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMjUpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIsIHNpemUgPSAyLjIpICsKICAgIGdncGxvdDI6Omdlb21fdGV4dCgKICAgICAgZGF0YSA9IHRvcF9sYWJlbHMsCiAgICAgIGdncGxvdDI6OmFlcyhsYWJlbCA9IGxhYmVsKSwKICAgICAgc2l6ZSA9IDIuNiwKICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsCiAgICAgIHZqdXN0ID0gLTAuNwogICAgKSArCiAgICBnZ3Bsb3QyOjpmYWNldF93cmFwKH4gY29tcGFyaXNvbiwgbmNvbCA9IDMpICsKICAgIGdncGxvdDI6OmNvb3JkX2VxdWFsKAogICAgICB4bGltID0gYygtYXhpc19saW1pdCwgYXhpc19saW1pdCksCiAgICAgIHlsaW0gPSBjKC1heGlzX2xpbWl0LCBheGlzX2xpbWl0KQogICAgKSArCiAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICB4ID0gIuW3puWBtOadoeS7tuOBruaomea6luWMluWFseWkiemHj+W5s+WdhyIsCiAgICAgIHkgPSAi5Y+z5YG05p2h5Lu244Gu5qiZ5rqW5YyW5YWx5aSJ6YeP5bmz5Z2HIiwKICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoCiAgICAgICAgc3R1ZHlfc3BlYyRzdHVkeV9sYWJlbCwKICAgICAgICAi77yaNDXluqbnt5rjgYvjgonjga7kuZbpm6LjgavjgojjgovlibLku5jjg5Djg6njg7PjgrnoqLrmlq0iCiAgICAgICksCiAgICAgIGNhcHRpb24gPSAi5ZCE54K544Gv5Zue562U6ICF5YWx5aSJ6YeP44G+44Gf44Gv5pSv5oyB5pS/5YWa44O75Zyw5Z+f44Gu44OA44Of44O85aSJ5pWw44CCNDXluqbnt5rjgavov5HjgYTjgbvjganmnaHku7bplpPjga7mp4vmiJDjgYzpoZ7kvLzjgIIiCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwLjUpICsKICAgIGdncGxvdDI6OnRoZW1lKAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZ2dwbG90Mjo6ZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgc3RyaXAudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikKICAgICkKICAKICB3cml0ZV9jc3ZfdW5pZmllZCgKICAgIGRpYWdvbmFsX2RmLAogICAgcGFzdGUwKHN0dWR5X3NwZWMkc3R1ZHlfaWQsICJfYXNzaWdubWVudF9iYWxhbmNlX2RpYWdvbmFsX2RhdGEuY3N2IikKICApCiAgCiAgc2F2ZV9wbG90X2JvdGgoCiAgICBwYXN0ZTAoc3R1ZHlfc3BlYyRzdHVkeV9pZCwgIl9hc3NpZ25tZW50X2JhbGFuY2VfZGlhZ29uYWxfcGxvdCIpLAogICAgcF9kaWFnb25hbCwKICAgIHdpZHRoID0gMTEuNSwKICAgIGhlaWdodCA9IDcuNQogICkKICAKICBsaXN0KAogICAgZGVzaWduID0gZGVzaWduLAogICAgcGFpcndpc2Vfc21kID0gcGFpcndpc2UsCiAgICBzdW1tYXJ5ID0gZ3JvdXBfc3VtbWFyeSwKICAgIGxvdmVfcGxvdCA9IHBfbG92ZSwKICAgIGRpYWdvbmFsX2RhdGEgPSBkaWFnb25hbF9kZiwKICAgIGRpYWdvbmFsX3Bsb3QgPSBwX2RpYWdvbmFsCiAgKQp9Cgphc3NpZ25tZW50X2JhbGFuY2VfcmVzdWx0cyA8LSBwdXJycjo6bWFwKAogIHN0dWR5X3NwZWNzLAogIG1ha2VfYmFsYW5jZV9vdXRwdXRzCikKCgptYWtlX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9vdXRwdXRzIDwtIGZ1bmN0aW9uKHN0dWR5X3NwZWMpIHsKICBlbnYgPC0gc3R1ZHlfc3BlYyRlbnYKICBhdHRyaWJ1dGVzIDwtIGVudiRhdHRyX3Rlcm1zCiAgCiAgcmFuZG9taXphdGlvbl9sb25nIDwtIGVudiRjb25qb2ludF9hbGxfbSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoCiAgICAgIElELAogICAgICBwYXJ0eV9uLAogICAgICB0YXNrLAogICAgICBwcm9maWxlLAogICAgICBkcGx5cjo6YWxsX29mKGF0dHJpYnV0ZXMpCiAgICApICU+JQogICAgdGlkeXI6OnBpdm90X2xvbmdlcigKICAgICAgY29scyA9IGRwbHlyOjphbGxfb2YoYXR0cmlidXRlcyksCiAgICAgIG5hbWVzX3RvID0gImF0dHJpYnV0ZSIsCiAgICAgIHZhbHVlc190byA9ICJsZXZlbCIKICAgICkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBsZXZlbCA9IGFzLmNoYXJhY3RlcihsZXZlbCksCiAgICAgIHBhcnR5X24gPSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihwYXJ0eV9uKSkKICAgICkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShsZXZlbCksIGxldmVsICE9ICIiKQogIAogIGZyZXF1ZW5jeSA8LSByYW5kb21pemF0aW9uX2xvbmcgJT4lCiAgICBkcGx5cjo6Y291bnQocGFydHlfbiwgYXR0cmlidXRlLCBsZXZlbCwgbmFtZSA9ICJvYnNlcnZlZF9uIikgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkocGFydHlfbiwgYXR0cmlidXRlKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIHRvdGFsX24gPSBzdW0ob2JzZXJ2ZWRfbiksCiAgICAgIG5fbGV2ZWxzID0gZHBseXI6Om4oKSwKICAgICAgb2JzZXJ2ZWRfc2hhcmUgPSBvYnNlcnZlZF9uIC8gdG90YWxfbiwKICAgICAgZXhwZWN0ZWRfc2hhcmUgPSAxIC8gbl9sZXZlbHMsCiAgICAgIGRldmlhdGlvbiA9IG9ic2VydmVkX3NoYXJlIC0gZXhwZWN0ZWRfc2hhcmUsCiAgICAgIGFic19kZXZpYXRpb24gPSBhYnMoZGV2aWF0aW9uKQogICAgKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkKICAKICB1bmlmb3JtaXR5X3Rlc3RzIDwtIGZyZXF1ZW5jeSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShwYXJ0eV9uLCBhdHRyaWJ1dGUpICU+JQogICAgZHBseXI6Omdyb3VwX21vZGlmeSgKICAgICAgfiB7CiAgICAgICAgdGVzdCA8LSBzdXBwcmVzc1dhcm5pbmdzKAogICAgICAgICAgc3RhdHM6OmNoaXNxLnRlc3QoCiAgICAgICAgICAgIHggPSAueCRvYnNlcnZlZF9uLAogICAgICAgICAgICBwID0gcmVwKDEgLyBucm93KC54KSwgbnJvdygueCkpCiAgICAgICAgICApCiAgICAgICAgKQogICAgICAgIHRpYmJsZTo6dGliYmxlKAogICAgICAgICAgY2hpX3NxdWFyZSA9IHVubmFtZSh0ZXN0JHN0YXRpc3RpYyksCiAgICAgICAgICBkZiA9IHVubmFtZSh0ZXN0JHBhcmFtZXRlciksCiAgICAgICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlLAogICAgICAgICAgbWF4X2Fic19zaGFyZV9kZXZpYXRpb24gPSBtYXgoLngkYWJzX2RldmlhdGlvbikKICAgICAgICApCiAgICAgIH0KICAgICkgJT4lCiAgICBkcGx5cjo6dW5ncm91cCgpICU+JQogICAgZHBseXI6Om11dGF0ZShwX2hvbG0gPSBzdGF0czo6cC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gImhvbG0iKSkKICAKICB3cml0ZV9jc3ZfdW5pZmllZCgKICAgIGZyZXF1ZW5jeSwKICAgIHBhc3RlMChzdHVkeV9zcGVjJHN0dWR5X2lkLCAiX3Byb2ZpbGVfbGV2ZWxfcmFuZG9taXphdGlvbl9mcmVxdWVuY3kuY3N2IikKICApCiAgd3JpdGVfY3N2X3VuaWZpZWQoCiAgICB1bmlmb3JtaXR5X3Rlc3RzLAogICAgcGFzdGUwKHN0dWR5X3NwZWMkc3R1ZHlfaWQsICJfcHJvZmlsZV9sZXZlbF9yYW5kb21pemF0aW9uX3Rlc3RzLmNzdiIpCiAgKQogIAogIHRvcF9mcmVxdWVuY3lfbGFiZWxzIDwtIGZyZXF1ZW5jeSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShwYXJ0eV9uLCBhdHRyaWJ1dGUpICU+JQogICAgZHBseXI6OnNsaWNlX21heChhYnNfZGV2aWF0aW9uLCBuID0gMSwgd2l0aF90aWVzID0gRkFMU0UpICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQogIAogIHBfcmFuZG9taXphdGlvbiA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICBmcmVxdWVuY3ksCiAgICBnZ3Bsb3QyOjphZXMoCiAgICAgIHggPSBleHBlY3RlZF9zaGFyZSwKICAgICAgeSA9IG9ic2VydmVkX3NoYXJlCiAgICApCiAgKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2FibGluZSgKICAgICAgaW50ZXJjZXB0ID0gMCwKICAgICAgc2xvcGUgPSAxLAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICBsaW5ld2lkdGggPSAwLjY1CiAgICApICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgIGdncGxvdDI6OmFlcyhzaGFwZSA9IGZhY3RvcihwYXJ0eV9uKSksCiAgICAgIHNpemUgPSAyLjIsCiAgICAgIGZpbGwgPSAid2hpdGUiCiAgICApICsKICAgIGdncGxvdDI6Omdlb21fdGV4dCgKICAgICAgZGF0YSA9IHRvcF9mcmVxdWVuY3lfbGFiZWxzLAogICAgICBnZ3Bsb3QyOjphZXMobGFiZWwgPSBsZXZlbCksCiAgICAgIHNpemUgPSAyLjQsCiAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLAogICAgICB2anVzdCA9IC0wLjcKICAgICkgKwogICAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IGF0dHJpYnV0ZSwgbmNvbCA9IDMpICsKICAgIGdncGxvdDI6OmNvb3JkX2VxdWFsKCkgKwogICAgZ2dwbG90Mjo6bGFicygKICAgICAgeCA9ICLoqK3oqIjkuIrjga7mnJ/lvoXmr5TnjociLAogICAgICB5ID0gIuims+a4rOavlOeOhyIsCiAgICAgIHNoYXBlID0gc3R1ZHlfc3BlYyRjb25kaXRpb25fbGFiZWwsCiAgICAgIHN1YnRpdGxlID0gcGFzdGUwKAogICAgICAgIHN0dWR5X3NwZWMkc3R1ZHlfbGFiZWwsCiAgICAgICAgIu+8muWxnuaAp+awtOa6luOBruims+a4rOavlOeOh+OBqOacn+W+heavlOeOhyIKICAgICAgKSwKICAgICAgY2FwdGlvbiA9ICLlkITngrnjga/lsZ7mgKfmsLTmupbDl+adoeS7tuOAgjQ15bqm57ea44Gr6L+R44GE44G744Gp5bGe5oCn5rC05rqW44Gu54Sh5L2c54K65o+Q56S644GM6Kit6KiI44Gp44GK44KK44CCIgogICAgKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMC41KSArCiAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGdncGxvdDI6OmVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgIHN0cmlwLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKQogICAgKQogIAogIHNhdmVfcGxvdF9ib3RoKAogICAgcGFzdGUwKHN0dWR5X3NwZWMkc3R1ZHlfaWQsICJfcHJvZmlsZV9yYW5kb21pemF0aW9uX2RpYWdvbmFsX3Bsb3QiKSwKICAgIHBfcmFuZG9taXphdGlvbiwKICAgIHdpZHRoID0gMTEsCiAgICBoZWlnaHQgPSBpZmVsc2Uoc3R1ZHlfc3BlYyRzdHVkeV9pZCA9PSAic3R1ZHkzIiwgNy41LCA4LjUpCiAgKQogIAogIGxpc3QoCiAgICBmcmVxdWVuY3kgPSBmcmVxdWVuY3ksCiAgICB1bmlmb3JtaXR5X3Rlc3RzID0gdW5pZm9ybWl0eV90ZXN0cywKICAgIHBsb3QgPSBwX3JhbmRvbWl6YXRpb24KICApCn0KCnByb2ZpbGVfcmFuZG9taXphdGlvbl9yZXN1bHRzIDwtIHB1cnJyOjptYXAoCiAgc3R1ZHlfc3BlY3MsCiAgbWFrZV9wcm9maWxlX3JhbmRvbWl6YXRpb25fb3V0cHV0cwopCgoKIyDoo5zpgbpI6Zai6YCj44Kz44O844OJCm1ha2VfdGVybV9sYWJlbF90YWJsZSA8LSBmdW5jdGlvbihlbnYpIHsKICBpZiAoZXhpc3RzKCJ0ZXJtX2xhYmVscyIsIGVudmlyID0gZW52LCBpbmhlcml0cyA9IEZBTFNFKSkgewogICAgb3V0IDwtIGdldCgidGVybV9sYWJlbHMiLCBlbnZpciA9IGVudikKICAgIHJlcXVpcmVkIDwtIGMoInRlcm0iLCAiYXR0cmlidXRlIiwgImxhYmVsIikKICAgIGlmIChhbGwocmVxdWlyZWQgJWluJSBuYW1lcyhvdXQpKSkgewogICAgICByZXR1cm4ob3V0ICU+JSBkcGx5cjo6c2VsZWN0KGRwbHlyOjphbnlfb2YoYyhyZXF1aXJlZCwgIm9yZGVyIikpKSkKICAgIH0KICB9CiAgCiAgdGliYmxlOjp0aWJibGUoCiAgICB0ZXJtID0gY2hhcmFjdGVyKCksCiAgICBhdHRyaWJ1dGUgPSBjaGFyYWN0ZXIoKSwKICAgIGxhYmVsID0gY2hhcmFjdGVyKCksCiAgICBvcmRlciA9IGludGVnZXIoKQogICkKfQoKcnVuX3N1cHBvcnRfYW1jZV9oZXRlcm9nZW5laXR5IDwtIGZ1bmN0aW9uKHN0dWR5X3NwZWMpIHsKICBlbnYgPC0gc3R1ZHlfc3BlYyRlbnYKICBzdHVkeV9pZCA8LSBzdHVkeV9zcGVjJHN0dWR5X2lkCiAgc3R1ZHlfbGFiZWwgPC0gc3R1ZHlfc3BlYyRzdHVkeV9sYWJlbAogIG91dF9kaXIgPC0gZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgcGFzdGUwKHN0dWR5X2lkLCAiX3BhcnR5X3N1cHBvcnQiKSkKICBkaXIuY3JlYXRlKG91dF9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQogIAogIHN1cHBvcnRfaWQgPC0gZW52JGNvdmFyX2lkICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgSUQgPSBhcy5jaGFyYWN0ZXIoSUQpLAogICAgICBwYXJ0eV9zdXBwb3J0X2ggPSBhcy5jaGFyYWN0ZXIocGFydHlfc3VwcG9ydF9mKQogICAgKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGRwbHlyOjpuYV9pZihwYXJ0eV9zdXBwb3J0X2gsICLmrKDmkI3jg7vnhKHlm57nrZQiKQogICAgKQogIAogIGRhdCA8LSBlbnYkY29uam9pbnRfYWxsX20gJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCiAgICAgIHBhcnR5X24gPSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihwYXJ0eV9uKSkKICAgICkgJT4lCiAgICBkcGx5cjo6bGVmdF9qb2luKHN1cHBvcnRfaWQsIGJ5ID0gIklEIikgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICAhaXMubmEocGFydHlfc3VwcG9ydF9oKSwKICAgICAgcGFydHlfc3VwcG9ydF9oICE9ICIiLAogICAgICAhcGFydHlfc3VwcG9ydF9oICVpbiUgZXhjbHVkZWRfc3VwcG9ydF9jYXRlZ29yaWVzCiAgICApCiAgCiAgc3VwcG9ydF9jb3VudHMgPC0gZGF0ICU+JQogICAgZHBseXI6OmRpc3RpbmN0KElELCBwYXJ0eV9uLCBwYXJ0eV9zdXBwb3J0X2gpICU+JQogICAgZHBseXI6OmNvdW50KHBhcnR5X3N1cHBvcnRfaCwgcGFydHlfbiwgbmFtZSA9ICJuX2NvbmRpdGlvbiIpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KHBhcnR5X3N1cHBvcnRfaCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBuX3RvdGFsID0gc3VtKG5fY29uZGl0aW9uKSwKICAgICAgbWluX2NvbmRpdGlvbl9uID0gbWluKG5fY29uZGl0aW9uKSwKICAgICAgY29uZGl0aW9uc19vYnNlcnZlZCA9IGRwbHlyOjpuX2Rpc3RpbmN0KHBhcnR5X24pCiAgICApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQogIAogIHN1cHBvcnRfdG90YWxzIDwtIGRhdCAlPiUKICAgIGRwbHlyOjpkaXN0aW5jdChJRCwgcGFydHlfc3VwcG9ydF9oKSAlPiUKICAgIGRwbHlyOjpjb3VudChwYXJ0eV9zdXBwb3J0X2gsIG5hbWUgPSAibl90b3RhbF9kaXN0aW5jdCIpCiAgCiAgc3VwcG9ydF9jb3VudHMgPC0gc3VwcG9ydF9jb3VudHMgJT4lCiAgICBkcGx5cjo6bGVmdF9qb2luKHN1cHBvcnRfdG90YWxzLCBieSA9ICJwYXJ0eV9zdXBwb3J0X2giKSAlPiUKICAgIGRwbHlyOjphcnJhbmdlKGRwbHlyOjpkZXNjKG5fdG90YWxfZGlzdGluY3QpLCBwYXJ0eV9zdXBwb3J0X2gpCiAgCiAgZWxpZ2libGVfZ3JvdXBzIDwtIHN1cHBvcnRfY291bnRzICU+JQogICAgZHBseXI6OmRpc3RpbmN0KAogICAgICBwYXJ0eV9zdXBwb3J0X2gsCiAgICAgIG5fdG90YWxfZGlzdGluY3QsCiAgICAgIG1pbl9jb25kaXRpb25fbiwKICAgICAgY29uZGl0aW9uc19vYnNlcnZlZAogICAgKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoCiAgICAgIG5fdG90YWxfZGlzdGluY3QgPj0gdW5pZmllZF9jb25maWckbWluX3N1cHBvcnRfdG90YWxfbiwKICAgICAgY29uZGl0aW9uc19vYnNlcnZlZCA9PSA0CiAgICApICU+JQogICAgZHBseXI6OnB1bGwocGFydHlfc3VwcG9ydF9oKQogIAogIHJlYWRyOjp3cml0ZV9jc3YoCiAgICBzdXBwb3J0X2NvdW50cywKICAgIGZpbGUucGF0aChvdXRfZGlyLCAicGFydHlfc3VwcG9ydF9zYW1wbGVfY291bnRzLmNzdiIpLAogICAgbmEgPSAiIgogICkKICAKICBmb3JtdWxhX3N1Ymdyb3VwIDwtIHN0YXRzOjphcy5mb3JtdWxhKAogICAgcGFzdGUoCiAgICAgICJzZWxlY3RlZCB+IiwKICAgICAgcGFzdGUoZW52JGF0dHJfdGVybXMsIGNvbGxhcHNlID0gIiArICIpCiAgICApCiAgKQogIAogIGVzdGltYXRlX29uZV9jZWxsIDwtIGZ1bmN0aW9uKGdyb3VwX3ZhbHVlLCBuX3ZhbHVlKSB7CiAgICBkYXRfY2VsbCA8LSBkYXQgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgcGFydHlfc3VwcG9ydF9oID09IGdyb3VwX3ZhbHVlLAogICAgICAgIHBhcnR5X24gPT0gbl92YWx1ZQogICAgICApCiAgICAKICAgIG5faWRzIDwtIGRwbHlyOjpuX2Rpc3RpbmN0KGRhdF9jZWxsJElEKQogICAgCiAgICBpZiAobl9pZHMgPCB1bmlmaWVkX2NvbmZpZyRtaW5fc3VwcG9ydF9jZWxsX24pIHsKICAgICAgcmV0dXJuKAogICAgICAgIHRpYmJsZTo6dGliYmxlKAogICAgICAgICAgdGVybSA9IE5BX2NoYXJhY3Rlcl8sCiAgICAgICAgICBlc3RpbWF0ZSA9IE5BX3JlYWxfLAogICAgICAgICAgc3RkLmVycm9yID0gTkFfcmVhbF8sCiAgICAgICAgICBzdGF0aXN0aWMgPSBOQV9yZWFsXywKICAgICAgICAgIHAudmFsdWUgPSBOQV9yZWFsXywKICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICBjb25mLmhpZ2ggPSBOQV9yZWFsXywKICAgICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGdyb3VwX3ZhbHVlLAogICAgICAgICAgcGFydHlfbiA9IG5fdmFsdWUsCiAgICAgICAgICBuX2lkcyA9IG5faWRzLAogICAgICAgICAgc3RhdHVzID0gImluc3VmZmljaWVudF9jZWxsX24iCiAgICAgICAgKQogICAgICApCiAgICB9CiAgICAKICAgIG1vZGVsIDwtIHRyeUNhdGNoKAogICAgICBmaXhlc3Q6OmZlb2xzKAogICAgICAgIGZvcm11bGFfc3ViZ3JvdXAsCiAgICAgICAgZGF0YSA9IGRhdF9jZWxsLAogICAgICAgIHZjb3YgPSB+IElECiAgICAgICksCiAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgZQogICAgKQogICAgCiAgICBpZiAoaW5oZXJpdHMobW9kZWwsICJlcnJvciIpKSB7CiAgICAgIHJldHVybigKICAgICAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICAgIHRlcm0gPSBOQV9jaGFyYWN0ZXJfLAogICAgICAgICAgZXN0aW1hdGUgPSBOQV9yZWFsXywKICAgICAgICAgIHN0ZC5lcnJvciA9IE5BX3JlYWxfLAogICAgICAgICAgc3RhdGlzdGljID0gTkFfcmVhbF8sCiAgICAgICAgICBwLnZhbHVlID0gTkFfcmVhbF8sCiAgICAgICAgICBjb25mLmxvdyA9IE5BX3JlYWxfLAogICAgICAgICAgY29uZi5oaWdoID0gTkFfcmVhbF8sCiAgICAgICAgICBwYXJ0eV9zdXBwb3J0X2ggPSBncm91cF92YWx1ZSwKICAgICAgICAgIHBhcnR5X24gPSBuX3ZhbHVlLAogICAgICAgICAgbl9pZHMgPSBuX2lkcywKICAgICAgICAgIHN0YXR1cyA9IHBhc3RlMCgibW9kZWxfZXJyb3I6ICIsIGNvbmRpdGlvbk1lc3NhZ2UobW9kZWwpKQogICAgICAgICkKICAgICAgKQogICAgfQogICAgCiAgICB0aWR5X2ZpeGVzdF91bmlmaWVkKG1vZGVsKSAlPiUKICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICBwYXJ0eV9zdXBwb3J0X2ggPSBncm91cF92YWx1ZSwKICAgICAgICBwYXJ0eV9uID0gbl92YWx1ZSwKICAgICAgICBuX2lkcyA9IG5faWRzLAogICAgICAgIHN0YXR1cyA9ICJlc3RpbWF0ZWQiCiAgICAgICkKICB9CiAgCiAgc3ViZ3JvdXBfY29lZmZpY2llbnRzIDwtIHB1cnJyOjptYXBfZGZyKAogICAgZWxpZ2libGVfZ3JvdXBzLAogICAgZnVuY3Rpb24oZ3JvdXBfdmFsdWUpIHsKICAgICAgcHVycnI6Om1hcF9kZnIoCiAgICAgICAgMjo1LAogICAgICAgIH4gZXN0aW1hdGVfb25lX2NlbGwoZ3JvdXBfdmFsdWUsIC54KQogICAgICApCiAgICB9CiAgKQogIAogIHRlcm1fbGFiZWxfdGFibGUgPC0gbWFrZV90ZXJtX2xhYmVsX3RhYmxlKGVudikKICAKICBzdWJncm91cF9jb2VmZmljaWVudHMgPC0gc3ViZ3JvdXBfY29lZmZpY2llbnRzICU+JQogICAgZHBseXI6OmxlZnRfam9pbih0ZXJtX2xhYmVsX3RhYmxlLCBieSA9ICJ0ZXJtIikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBhdHRyaWJ1dGUgPSBkcGx5cjo6Y29hbGVzY2UoYXR0cmlidXRlLCAi44Gd44Gu5LuWIiksCiAgICAgIGxhYmVsID0gZHBseXI6OmNvYWxlc2NlKGxhYmVsLCB0ZXJtKSwKICAgICAgZXN0aW1hdGVfcHAgPSBlc3RpbWF0ZSAqIDEwMCwKICAgICAgY29uZi5sb3dfcHAgPSBjb25mLmxvdyAqIDEwMCwKICAgICAgY29uZi5oaWdoX3BwID0gY29uZi5oaWdoICogMTAwLAogICAgICBwYXJ0eV9uX2xhYmVsID0gZmFjdG9yKAogICAgICAgIHBhcnR5X24sCiAgICAgICAgbGV2ZWxzID0gMjo1LAogICAgICAgIGxhYmVscyA9IHBhc3RlMCgyOjUsIGlmZWxzZShzdHVkeV9pZCA9PSAic3R1ZHkzIiwgIumBuOaKnuiCoiIsICLmlL/lhZoiKSkKICAgICAgKQogICAgKQogIAogIHJlYWRyOjp3cml0ZV9jc3YoCiAgICBzdWJncm91cF9jb2VmZmljaWVudHMsCiAgICBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X3N1cHBvcnRfc3ViZ3JvdXBfYW1jZV9jb2VmZmljaWVudHMuY3N2IiksCiAgICBuYSA9ICIiCiAgKQogIAogIGZvciAoZ3JvdXBfdmFsdWUgaW4gZWxpZ2libGVfZ3JvdXBzKSB7CiAgICBwbG90X2RhdCA8LSBzdWJncm91cF9jb2VmZmljaWVudHMgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgcGFydHlfc3VwcG9ydF9oID09IGdyb3VwX3ZhbHVlLAogICAgICAgIHN0YXR1cyA9PSAiZXN0aW1hdGVkIiwKICAgICAgICAhaXMubmEodGVybSkKICAgICAgKQogICAgCiAgICBpZiAobnJvdyhwbG90X2RhdCkgPT0gMCkgbmV4dAogICAgCiAgICBsYWJlbF9vcmRlciA8LSBwbG90X2RhdCAlPiUKICAgICAgZHBseXI6OmFycmFuZ2UoYXR0cmlidXRlLCBkcGx5cjo6Y29hbGVzY2Uob3JkZXIsIDk5OTkpLCBsYWJlbCkgJT4lCiAgICAgIGRwbHlyOjpkaXN0aW5jdChsYWJlbCkgJT4lCiAgICAgIGRwbHlyOjpwdWxsKGxhYmVsKQogICAgCiAgICBwbG90X2RhdCA8LSBwbG90X2RhdCAlPiUKICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICBsYWJlbCA9IGZhY3RvcihsYWJlbCwgbGV2ZWxzID0gcmV2KGxhYmVsX29yZGVyKSkKICAgICAgKQogICAgCiAgICBuX2dyb3VwIDwtIHN1cHBvcnRfdG90YWxzICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKHBhcnR5X3N1cHBvcnRfaCA9PSBncm91cF92YWx1ZSkgJT4lCiAgICAgIGRwbHlyOjpwdWxsKG5fdG90YWxfZGlzdGluY3QpCiAgICAKICAgIHBfZ3JvdXAgPC0gZ2dwbG90Mjo6Z2dwbG90KAogICAgICBwbG90X2RhdCwKICAgICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBlc3RpbWF0ZV9wcCwKICAgICAgICB5ID0gbGFiZWwsCiAgICAgICAgc2hhcGUgPSBwYXJ0eV9uX2xhYmVsCiAgICAgICkKICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjQ1KSArCiAgICAgIGdncGxvdDI6Omdlb21fZXJyb3JiYXJoKAogICAgICAgIGdncGxvdDI6OmFlcygKICAgICAgICAgIHhtaW4gPSBjb25mLmxvd19wcCwKICAgICAgICAgIHhtYXggPSBjb25mLmhpZ2hfcHAKICAgICAgICApLAogICAgICAgIGhlaWdodCA9IDAuMTAsCiAgICAgICAgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNTUpLAogICAgICAgIGxpbmV3aWR0aCA9IDAuNTUKICAgICAgKSArCiAgICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgICAgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNTUpLAogICAgICAgIHNpemUgPSAyLjMsCiAgICAgICAgZmlsbCA9ICJ3aGl0ZSIKICAgICAgKSArCiAgICAgIGdncGxvdDI6OmZhY2V0X2dyaWQoCiAgICAgICAgYXR0cmlidXRlIH4gLiwKICAgICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgICBzcGFjZSA9ICJmcmVlX3kiCiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICAgIHggPSAi6YG45oqe56K6546H44G444Gu5Yq55p6c77yIcGVyY2VudGFnZSBwb2ludHPvvIkiLAogICAgICAgIHkgPSBOVUxMLAogICAgICAgIHNoYXBlID0gc3R1ZHlfc3BlYyRjb25kaXRpb25fbGFiZWwsCiAgICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoCiAgICAgICAgICBzdHVkeV9sYWJlbCwKICAgICAgICAgICLvvJoiLAogICAgICAgICAgZ3JvdXBfdmFsdWUsCiAgICAgICAgICAi5pSv5oyB6ICF77yIbiA9ICIsCiAgICAgICAgICBzY2FsZXM6OmNvbW1hKG5fZ3JvdXApLAogICAgICAgICAgIu+8iSIKICAgICAgICApLAogICAgICAgIGNhcHRpb24gPSBwYXN0ZTAoCiAgICAgICAgICAi5Zue562U6ICFSUTjgafjgq/jg6njgrnjgr/ljJbjgZfjgZ/mqJnmupboqqTlt67jgILlkITmnaHku7bjgrvjg6tuIDwgIiwKICAgICAgICAgIHVuaWZpZWRfY29uZmlnJG1pbl9zdXBwb3J0X2NlbGxfbiwKICAgICAgICAgICLjga/mjqjlrprjgZfjgarjgYTjgIIiCiAgICAgICAgKQogICAgICApICsKICAgICAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTAuNSkgKwogICAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBnZ3Bsb3QyOjplbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHN0cmlwLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikKICAgICAgKQogICAgCiAgICBncm91cF9pbmRleCA8LSBtYXRjaChncm91cF92YWx1ZSwgZWxpZ2libGVfZ3JvdXBzKQogICAgZmlsZV9zdHViIDwtIHBhc3RlMCgKICAgICAgc3R1ZHlfaWQsCiAgICAgICJfcGFydHlfc3VwcG9ydF9hbWNlXyIsCiAgICAgIHNwcmludGYoIiUwMmQiLCBncm91cF9pbmRleCksCiAgICAgICJfIiwKICAgICAgc2FmZV9maWxlbmFtZShncm91cF92YWx1ZSkKICAgICkKICAgIAogICAgZ2dwbG90Mjo6Z2dzYXZlKAogICAgICBmaWxlbmFtZSA9IGZpbGUucGF0aChvdXRfZGlyLCBwYXN0ZTAoZmlsZV9zdHViLCAiLnBuZyIpKSwKICAgICAgcGxvdCA9IHBfZ3JvdXAsCiAgICAgIHdpZHRoID0gMTAuNSwKICAgICAgaGVpZ2h0ID0gaWZlbHNlKHN0dWR5X2lkID09ICJzdHVkeTMiLCAxMS41LCAxMC4wKSwKICAgICAgZHBpID0gNDAwLAogICAgICBiZyA9ICJ3aGl0ZSIKICAgICkKICAgIAogICAgZ2dwbG90Mjo6Z2dzYXZlKAogICAgICBmaWxlbmFtZSA9IGZpbGUucGF0aChvdXRfZGlyLCBwYXN0ZTAoZmlsZV9zdHViLCAiLnBkZiIpKSwKICAgICAgcGxvdCA9IHBfZ3JvdXAsCiAgICAgIHdpZHRoID0gMTAuNSwKICAgICAgaGVpZ2h0ID0gaWZlbHNlKHN0dWR5X2lkID09ICJzdHVkeTMiLCAxMS41LCAxMC4wKSwKICAgICAgZGV2aWNlID0gZ3JEZXZpY2VzOjpjYWlyb19wZGYsCiAgICAgIGJnID0gIndoaXRlIgogICAgKQogIH0KICAKICBpbnRlcmFjdGlvbl9tb2RlbHMgPC0gbGlzdCgpCiAgaW50ZXJhY3Rpb25fdGVzdF90ZXh0IDwtIGNoYXJhY3RlcigpCiAgCiAgZGF0X2ludGVyYWN0aW9uIDwtIGRhdCAlPiUKICAgIGRwbHlyOjpmaWx0ZXIocGFydHlfc3VwcG9ydF9oICVpbiUgZWxpZ2libGVfZ3JvdXBzKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGZhY3RvcihwYXJ0eV9zdXBwb3J0X2gpCiAgICApCiAgCiAgaWYgKCLmlK/mjIHmlL/lhZrjgarjgZciICVpbiUgbGV2ZWxzKGRhdF9pbnRlcmFjdGlvbiRwYXJ0eV9zdXBwb3J0X2gpKSB7CiAgICBkYXRfaW50ZXJhY3Rpb24gPC0gZGF0X2ludGVyYWN0aW9uICU+JQogICAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IHN0YXRzOjpyZWxldmVsKAogICAgICAgICAgcGFydHlfc3VwcG9ydF9oLAogICAgICAgICAgcmVmID0gIuaUr+aMgeaUv+WFmuOBquOBlyIKICAgICAgICApCiAgICAgICkKICB9IGVsc2UgaWYgKG5yb3coc3VwcG9ydF90b3RhbHMpID4gMCkgewogICAgbGFyZ2VzdF9ncm91cCA8LSBzdXBwb3J0X3RvdGFscyAlPiUKICAgICAgZHBseXI6OmZpbHRlcihwYXJ0eV9zdXBwb3J0X2ggJWluJSBlbGlnaWJsZV9ncm91cHMpICU+JQogICAgICBkcGx5cjo6c2xpY2VfbWF4KG5fdG90YWxfZGlzdGluY3QsIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgICAgIGRwbHlyOjpwdWxsKHBhcnR5X3N1cHBvcnRfaCkKICAgIAogICAgaWYgKGxlbmd0aChsYXJnZXN0X2dyb3VwKSA9PSAxKSB7CiAgICAgIGRhdF9pbnRlcmFjdGlvbiA8LSBkYXRfaW50ZXJhY3Rpb24gJT4lCiAgICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IHN0YXRzOjpyZWxldmVsKAogICAgICAgICAgICBwYXJ0eV9zdXBwb3J0X2gsCiAgICAgICAgICAgIHJlZiA9IGxhcmdlc3RfZ3JvdXAKICAgICAgICAgICkKICAgICAgICApCiAgICB9CiAgfQogIAogIGZvcm11bGFfaW50ZXJhY3Rpb24gPC0gc3RhdHM6OmFzLmZvcm11bGEoCiAgICBwYXN0ZTAoCiAgICAgICJzZWxlY3RlZCB+IHBhcnR5X3N1cHBvcnRfaCAqICgiLAogICAgICBwYXN0ZShlbnYkYXR0cl90ZXJtcywgY29sbGFwc2UgPSAiICsgIiksCiAgICAgICIpIgogICAgKQogICkKICAKICBmb3IgKG5fdmFsdWUgaW4gMjo1KSB7CiAgICBkYXRfbiA8LSBkYXRfaW50ZXJhY3Rpb24gJT4lIGRwbHlyOjpmaWx0ZXIocGFydHlfbiA9PSBuX3ZhbHVlKQogICAgCiAgICBtb2RlbF9uIDwtIHRyeUNhdGNoKAogICAgICBmaXhlc3Q6OmZlb2xzKAogICAgICAgIGZvcm11bGFfaW50ZXJhY3Rpb24sCiAgICAgICAgZGF0YSA9IGRhdF9uLAogICAgICAgIHZjb3YgPSB+IElECiAgICAgICksCiAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgZQogICAgKQogICAgCiAgICBpbnRlcmFjdGlvbl9tb2RlbHNbW2FzLmNoYXJhY3RlcihuX3ZhbHVlKV1dIDwtIG1vZGVsX24KICAgIAogICAgaW50ZXJhY3Rpb25fdGVzdF90ZXh0IDwtIGMoCiAgICAgIGludGVyYWN0aW9uX3Rlc3RfdGV4dCwKICAgICAgcGFzdGUwKCJcbj09PT09ICIsIHN0dWR5X2xhYmVsLCAiOiBjb25kaXRpb24gIiwgbl92YWx1ZSwgIiA9PT09PVxuIikKICAgICkKICAgIAogICAgaWYgKGluaGVyaXRzKG1vZGVsX24sICJlcnJvciIpKSB7CiAgICAgIGludGVyYWN0aW9uX3Rlc3RfdGV4dCA8LSBjKAogICAgICAgIGludGVyYWN0aW9uX3Rlc3RfdGV4dCwKICAgICAgICBwYXN0ZTAoIk1vZGVsIGVycm9yOiAiLCBjb25kaXRpb25NZXNzYWdlKG1vZGVsX24pLCAiXG4iKQogICAgICApCiAgICB9IGVsc2UgewogICAgICBpbnRlcmFjdGlvbl90ZXN0X3RleHQgPC0gYygKICAgICAgICBpbnRlcmFjdGlvbl90ZXN0X3RleHQsCiAgICAgICAgY2FwdHVyZS5vdXRwdXQoc3VtbWFyeShtb2RlbF9uKSksCiAgICAgICAgIlxuLS0tIEpvaW50IFdhbGQgdGVzdCBmb3IgcGFydHktc3VwcG9ydCBpbnRlcmFjdGlvbiB0ZXJtcyAtLS1cbiIsCiAgICAgICAgdHJ5Q2F0Y2goCiAgICAgICAgICBjYXB0dXJlLm91dHB1dCgKICAgICAgICAgICAgZml4ZXN0Ojp3YWxkKAogICAgICAgICAgICAgIG1vZGVsX24sCiAgICAgICAgICAgICAga2VlcCA9ICJwYXJ0eV9zdXBwb3J0X2guKjp8OnBhcnR5X3N1cHBvcnRfaCIKICAgICAgICAgICAgKQogICAgICAgICAgKSwKICAgICAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgcGFzdGUwKCJXYWxkIHRlc3QgZXJyb3I6ICIsIGNvbmRpdGlvbk1lc3NhZ2UoZSkpCiAgICAgICAgKQogICAgICApCiAgICB9CiAgfQogIAogIHdyaXRlTGluZXMoCiAgICBpbnRlcmFjdGlvbl90ZXN0X3RleHQsCiAgICBjb24gPSBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X3N1cHBvcnRfaW50ZXJhY3Rpb25fbW9kZWxzX2FuZF93YWxkX3Rlc3RzLnR4dCIpCiAgKQogIAogIGxpc3QoCiAgICBzdXBwb3J0X2NvdW50cyA9IHN1cHBvcnRfY291bnRzLAogICAgZWxpZ2libGVfZ3JvdXBzID0gZWxpZ2libGVfZ3JvdXBzLAogICAgc3ViZ3JvdXBfY29lZmZpY2llbnRzID0gc3ViZ3JvdXBfY29lZmZpY2llbnRzLAogICAgaW50ZXJhY3Rpb25fbW9kZWxzID0gaW50ZXJhY3Rpb25fbW9kZWxzLAogICAgZGF0YSA9IGRhdAogICkKfQoKcGFydHlfc3VwcG9ydF9hbWNlX3Jlc3VsdHMgPC0gcHVycnI6Om1hcCgKICBzdHVkeV9zcGVjcywKICBydW5fc3VwcG9ydF9hbWNlX2hldGVyb2dlbmVpdHkKKQoKcnVuX3N1cHBvcnRfcmVsYXRpdmVfY3VlIDwtIGZ1bmN0aW9uKHN0dWR5X3NwZWMsIGFtY2VfcmVzdWx0KSB7CiAgZW52IDwtIHN0dWR5X3NwZWMkZW52CiAgc3R1ZHlfaWQgPC0gc3R1ZHlfc3BlYyRzdHVkeV9pZAogIG91dF9kaXIgPC0gZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgcGFzdGUwKHN0dWR5X2lkLCAiX3BhcnR5X3N1cHBvcnQiKSkKICAKICBkYXQgPC0gYW1jZV9yZXN1bHQkZGF0YQogIGVsaWdpYmxlX2dyb3VwcyA8LSBhbWNlX3Jlc3VsdCRlbGlnaWJsZV9ncm91cHMKICAKICBvYnNlcnZlZF9saXN0IDwtIGxpc3QoKQogIGludGVydmFsX2xpc3QgPC0gbGlzdCgpCiAgc2xvcGVfbGlzdCA8LSBsaXN0KCkKICBmYWlsdXJlX2xpc3QgPC0gbGlzdCgpCiAgCiAgZm9yIChncm91cF9pbmRleCBpbiBzZXFfYWxvbmcoZWxpZ2libGVfZ3JvdXBzKSkgewogICAgZ3JvdXBfdmFsdWUgPC0gZWxpZ2libGVfZ3JvdXBzW2dyb3VwX2luZGV4XQogICAgZGF0X2dyb3VwIDwtIGRhdCAlPiUKICAgICAgZHBseXI6OmZpbHRlcihwYXJ0eV9zdXBwb3J0X2ggPT0gZ3JvdXBfdmFsdWUpCiAgICAKICAgIGNvbmRpdGlvbl9jb3VudHMgPC0gZGF0X2dyb3VwICU+JQogICAgICBkcGx5cjo6ZGlzdGluY3QoSUQsIHBhcnR5X24pICU+JQogICAgICBkcGx5cjo6Y291bnQocGFydHlfbiwgbmFtZSA9ICJuX2lkcyIpCiAgICAKICAgIGlmICgKICAgICAgIWlkZW50aWNhbChzb3J0KGNvbmRpdGlvbl9jb3VudHMkcGFydHlfbiksIDI6NSkgfHwKICAgICAgYW55KGNvbmRpdGlvbl9jb3VudHMkbl9pZHMgPCB1bmlmaWVkX2NvbmZpZyRtaW5fc3VwcG9ydF9jZWxsX24pCiAgICApIHsKICAgICAgZmFpbHVyZV9saXN0W1tncm91cF92YWx1ZV1dIDwtIHRpYmJsZTo6dGliYmxlKAogICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGdyb3VwX3ZhbHVlLAogICAgICAgIHJlYXNvbiA9ICJOb3QgYWxsIGZvdXIgY29uZGl0aW9ucyBtZWV0IHRoZSBtaW5pbXVtIGNlbGwgc2l6ZSIKICAgICAgKQogICAgICBuZXh0CiAgICB9CiAgICAKICAgIHByZXBhcmVkIDwtIHRyeUNhdGNoKAogICAgICBlbnYkcHJlcGFyZV9yZWxhdGl2ZV9jdWVfYW5hbHlzaXMoCiAgICAgICAgZGF0YSA9IGRhdF9ncm91cCwKICAgICAgICBjdWVfbWFwID0gZW52JHJlbGF0aXZlX2N1ZV9tYXAKICAgICAgKSwKICAgICAgZXJyb3IgPSBmdW5jdGlvbihlKSBlCiAgICApCiAgICAKICAgIGlmIChpbmhlcml0cyhwcmVwYXJlZCwgImVycm9yIikpIHsKICAgICAgZmFpbHVyZV9saXN0W1tncm91cF92YWx1ZV1dIDwtIHRpYmJsZTo6dGliYmxlKAogICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGdyb3VwX3ZhbHVlLAogICAgICAgIHJlYXNvbiA9IGNvbmRpdGlvbk1lc3NhZ2UocHJlcGFyZWQpCiAgICAgICkKICAgICAgbmV4dAogICAgfQogICAgCiAgICBvYnNlcnZlZCA8LSBlbnYkZXN0aW1hdGVfcmVsYXRpdmVfY3VlX2luZGljZXMocHJlcGFyZWQpCiAgICBvYnNlcnZlZF9zbG9wZXMgPC0gZW52JGVzdGltYXRlX3JlbGF0aXZlX2N1ZV9zbG9wZXMoCiAgICAgIG9ic2VydmVkJGN1ZV9pbXBvcnRhbmNlCiAgICApCiAgICAKICAgIG9ic2VydmVkX2xpc3RbW2dyb3VwX3ZhbHVlXV0gPC0gb2JzZXJ2ZWQkY3VlX2ltcG9ydGFuY2UgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgcGFydHlfc3VwcG9ydF9oID0gZ3JvdXBfdmFsdWUsCiAgICAgICAgLmJlZm9yZSA9IDEKICAgICAgKQogICAgCiAgICBzbG9wZV9saXN0W1tncm91cF92YWx1ZV1dIDwtIHRpYmJsZTo6dGliYmxlKAogICAgICBwYXJ0eV9zdXBwb3J0X2ggPSBncm91cF92YWx1ZSwKICAgICAgc3RhdGlzdGljID0gbmFtZXMob2JzZXJ2ZWRfc2xvcGVzKSwKICAgICAgZXN0aW1hdGUgPSBhcy5udW1lcmljKG9ic2VydmVkX3Nsb3BlcykKICAgICkKICAgIAogICAgQiA8LSB1bmlmaWVkX2NvbmZpZyRzdXBwb3J0X2Jvb3RzdHJhcF9CCiAgICAKICAgIGlmIChCID4gMCkgewogICAgICBjYWNoZV9maWxlIDwtIGZpbGUucGF0aCgKICAgICAgICBvdXRfZGlyLAogICAgICAgIHBhc3RlMCgKICAgICAgICAgICJzdXBwb3J0X3JlbGF0aXZlX2N1ZV9ib290c3RyYXBfIiwKICAgICAgICAgIHVuaWZpZWRfY29uZmlnJGN1ZV9pbXBvcnRhbmNlX21ldHJpY192ZXJzaW9uLAogICAgICAgICAgIl8iLAogICAgICAgICAgc3ByaW50ZigiJTAyZCIsIGdyb3VwX2luZGV4KSwKICAgICAgICAgICJfQiIsCiAgICAgICAgICBCLAogICAgICAgICAgIi5yZHMiCiAgICAgICAgKQogICAgICApCiAgICAgIAogICAgICBpZiAoCiAgICAgICAgZmlsZS5leGlzdHMoY2FjaGVfZmlsZSkgJiYKICAgICAgICAhdW5pZmllZF9jb25maWckcmVydW5fc3VwcG9ydF9ib290c3RyYXAKICAgICAgKSB7CiAgICAgICAgYm9vdHN0cmFwX3Jlc3VsdCA8LSByZWFkUkRTKGNhY2hlX2ZpbGUpCiAgICAgIH0gZWxzZSB7CiAgICAgICAgYm9vdHN0cmFwX3Jlc3VsdCA8LSBlbnYkcnVuX3JlbGF0aXZlX2N1ZV9ib290c3RyYXAoCiAgICAgICAgICBwcmVwYXJlZCA9IHByZXBhcmVkLAogICAgICAgICAgQiA9IEIsCiAgICAgICAgICBzZWVkID0gdW5pZmllZF9jb25maWckc3VwcG9ydF9ib290c3RyYXBfc2VlZCArCiAgICAgICAgICAgIDEwMDAgKiBtYXRjaChzdHVkeV9pZCwgbmFtZXMoc3R1ZHlfc3BlY3MpKSArCiAgICAgICAgICAgIGdyb3VwX2luZGV4LAogICAgICAgICAgcHJvZ3Jlc3NfZXZlcnkgPSBtYXgoMCwgZmxvb3IoQiAvIDUpKQogICAgICAgICkKICAgICAgICBzYXZlUkRTKGJvb3RzdHJhcF9yZXN1bHQsIGNhY2hlX2ZpbGUpCiAgICAgIH0KICAgICAgCiAgICAgIGludGVydmFscyA8LSBlbnYkc3VtbWFyaXNlX2NvbmRpdGlvbl9pbnRlcnZhbHMoCiAgICAgICAgb2JzZXJ2ZWRfY3VlX2ltcG9ydGFuY2UgPSBvYnNlcnZlZCRjdWVfaW1wb3J0YW5jZSwKICAgICAgICBib290c3RyYXBfY29uZGl0aW9uX3Jlc3VsdHMgPSBib290c3RyYXBfcmVzdWx0JGNvbmRpdGlvbl9lc3RpbWF0ZXMKICAgICAgKSAlPiUKICAgICAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgICAgcGFydHlfc3VwcG9ydF9oID0gZ3JvdXBfdmFsdWUsCiAgICAgICAgICAuYmVmb3JlID0gMQogICAgICAgICkKICAgICAgCiAgICAgIHNsb3BlX2luZmVyZW5jZSA8LSBlbnYkc3VtbWFyaXNlX3Nsb3BlX2luZmVyZW5jZSgKICAgICAgICBvYnNlcnZlZF9zbG9wZXMgPSBvYnNlcnZlZF9zbG9wZXMsCiAgICAgICAgYm9vdHN0cmFwX3Nsb3BlcyA9IGJvb3RzdHJhcF9yZXN1bHQkc2xvcGVzCiAgICAgICkgJT4lCiAgICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICAgIHBhcnR5X3N1cHBvcnRfaCA9IGdyb3VwX3ZhbHVlLAogICAgICAgICAgLmJlZm9yZSA9IDEKICAgICAgICApCiAgICAgIAogICAgICBpbnRlcnZhbF9saXN0W1tncm91cF92YWx1ZV1dIDwtIGludGVydmFscwogICAgICBzbG9wZV9saXN0W1twYXN0ZTAoZ3JvdXBfdmFsdWUsICJfaW5mZXJlbmNlIildXSA8LSBzbG9wZV9pbmZlcmVuY2UKICAgIH0KICB9CiAgCiAgb2JzZXJ2ZWRfZGYgPC0gZHBseXI6OmJpbmRfcm93cyhvYnNlcnZlZF9saXN0KQogIGludGVydmFsX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MoaW50ZXJ2YWxfbGlzdCkKICBzbG9wZV9kZiA8LSBkcGx5cjo6YmluZF9yb3dzKHNsb3BlX2xpc3QpCiAgZmFpbHVyZXNfZGYgPC0gZHBseXI6OmJpbmRfcm93cyhmYWlsdXJlX2xpc3QpCiAgCiAgcmVhZHI6OndyaXRlX2NzdigKICAgIG9ic2VydmVkX2RmLAogICAgZmlsZS5wYXRoKG91dF9kaXIsICJwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV9vYnNlcnZlZC5jc3YiKSwKICAgIG5hID0gIiIKICApCiAgcmVhZHI6OndyaXRlX2NzdigKICAgIGludGVydmFsX2RmLAogICAgZmlsZS5wYXRoKG91dF9kaXIsICJwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV9pbnRlcnZhbHMuY3N2IiksCiAgICBuYSA9ICIiCiAgKQogIHJlYWRyOjp3cml0ZV9jc3YoCiAgICBzbG9wZV9kZiwKICAgIGZpbGUucGF0aChvdXRfZGlyLCAicGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWVfc2xvcGVzLmNzdiIpLAogICAgbmEgPSAiIgogICkKICByZWFkcjo6d3JpdGVfY3N2KAogICAgZmFpbHVyZXNfZGYsCiAgICBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X3N1cHBvcnRfcmVsYXRpdmVfY3VlX2ZhaWx1cmVzLmNzdiIpLAogICAgbmEgPSAiIgogICkKICAKICBpZiAobnJvdyhpbnRlcnZhbF9kZikgPiAwKSB7CiAgICBwbG90X2RmIDwtIGludGVydmFsX2RmICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKHN0YXRpc3RpYyA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIikgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgZXN0aW1hdGVfcGN0ID0gZXN0aW1hdGUgKiAxMDAsCiAgICAgICAgY29uZl9sb3dfcGN0ID0gY29uZl9sb3cgKiAxMDAsCiAgICAgICAgY29uZl9oaWdoX3BjdCA9IGNvbmZfaGlnaCAqIDEwMAogICAgICApCiAgfSBlbHNlIHsKICAgIHBsb3RfZGYgPC0gb2JzZXJ2ZWRfZGYgJT4lCiAgICAgIGRwbHlyOjp0cmFuc211dGUoCiAgICAgICAgcGFydHlfc3VwcG9ydF9oLAogICAgICAgIHBhcnR5X24sCiAgICAgICAgZXN0aW1hdGVfcGN0ID0gcmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlICogMTAwLAogICAgICAgIGNvbmZfbG93X3BjdCA9IE5BX3JlYWxfLAogICAgICAgIGNvbmZfaGlnaF9wY3QgPSBOQV9yZWFsXwogICAgICApCiAgfQogIAogIGlmIChucm93KHBsb3RfZGYpID4gMCkgewogICAgcF9yZWxhdGl2ZV9zdXBwb3J0IDwtIGdncGxvdDI6OmdncGxvdCgKICAgICAgcGxvdF9kZiwKICAgICAgZ2dwbG90Mjo6YWVzKAogICAgICAgIHggPSBwYXJ0eV9uLAogICAgICAgIHkgPSBlc3RpbWF0ZV9wY3QsCiAgICAgICAgZ3JvdXAgPSAxCiAgICAgICkKICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC40NSkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX2xpbmUobGluZXdpZHRoID0gMC43MCkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX2Vycm9yYmFyKAogICAgICAgIGdncGxvdDI6OmFlcygKICAgICAgICAgIHltaW4gPSBjb25mX2xvd19wY3QsCiAgICAgICAgICB5bWF4ID0gY29uZl9oaWdoX3BjdAogICAgICAgICksCiAgICAgICAgd2lkdGggPSAwLjA4LAogICAgICAgIGxpbmV3aWR0aCA9IDAuNTUsCiAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiLCBzaXplID0gMi41KSArCiAgICAgIGdncGxvdDI6OmZhY2V0X3dyYXAofiBwYXJ0eV9zdXBwb3J0X2gsIG5jb2wgPSAzKSArCiAgICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cygKICAgICAgICBicmVha3MgPSAyOjUsCiAgICAgICAgbGFiZWxzID0gcGFzdGUwKDI6NSwgaWZlbHNlKHN0dWR5X2lkID09ICJzdHVkeTMiLCAi6YG45oqe6IKiIiwgIuaUv+WFmiIpKQogICAgICApICsKICAgICAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKAogICAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiJSIpLAogICAgICAgIGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gNikKICAgICAgKSArCiAgICAgIGdncGxvdDI6OmxhYnMoCiAgICAgICAgeCA9IHN0dWR5X3NwZWMkY29uZGl0aW9uX2xhYmVsLAogICAgICAgIHkgPSAi5pS/5YWa5omL44GM44GL44KK44Gu55u45a++5q+U6YeNIiwKICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgKICAgICAgICAgIHN0dWR5X3NwZWMkc3R1ZHlfbGFiZWwsCiAgICAgICAgICAi77ya5pSv5oyB5pS/5YWa5Yil44Gu5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeNIgogICAgICAgICksCiAgICAgICAgY2FwdGlvbiA9IHBhc3RlMCgKICAgICAgICAgICLlkITlsZ7mgKflhoXjga7pmZDnlYzlubPlnYfjga7lubPlnYfntbblr77jg5rjgqLlt67jgavln7rjgaXjgY/jgIIiLAogICAgICAgICAgaWZlbHNlKAogICAgICAgICAgICB1bmlmaWVkX2NvbmZpZyRzdXBwb3J0X2Jvb3RzdHJhcF9CID4gMCwKICAgICAgICAgICAgcGFzdGUwKAogICAgICAgICAgICAgICI5NSXkv6HpoLzljLrplpPjga/lm57nrZTogIXjgq/jg6njgrnjgr/jg7vjg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5fvvIhCID0gIiwKICAgICAgICAgICAgICB1bmlmaWVkX2NvbmZpZyRzdXBwb3J0X2Jvb3RzdHJhcF9CLAogICAgICAgICAgICAgICLvvInjgIIiCiAgICAgICAgICAgICksCiAgICAgICAgICAgICLkv6HpoLzljLrplpPjga/mnKroqIjnrpfjgIIiCiAgICAgICAgICApCiAgICAgICAgKQogICAgICApICsKICAgICAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTAuNSkgKwogICAgICBnZ3Bsb3QyOjp0aGVtZSgKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBnZ3Bsb3QyOjplbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHN0cmlwLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikKICAgICAgKQogICAgCiAgICBnZ3Bsb3QyOjpnZ3NhdmUoCiAgICAgIGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dF9kaXIsICJwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV93ZWlnaHQucG5nIiksCiAgICAgIHBsb3QgPSBwX3JlbGF0aXZlX3N1cHBvcnQsCiAgICAgIHdpZHRoID0gMTEuNSwKICAgICAgaGVpZ2h0ID0gbWF4KDcuMCwgMi42ICogY2VpbGluZyhkcGx5cjo6bl9kaXN0aW5jdChwbG90X2RmJHBhcnR5X3N1cHBvcnRfaCkgLyAzKSksCiAgICAgIGRwaSA9IDQwMCwKICAgICAgYmcgPSAid2hpdGUiCiAgICApCiAgICAKICAgIGdncGxvdDI6Omdnc2F2ZSgKICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X3N1cHBvcnRfcmVsYXRpdmVfY3VlX3dlaWdodC5wZGYiKSwKICAgICAgcGxvdCA9IHBfcmVsYXRpdmVfc3VwcG9ydCwKICAgICAgd2lkdGggPSAxMS41LAogICAgICBoZWlnaHQgPSBtYXgoNy4wLCAyLjYgKiBjZWlsaW5nKGRwbHlyOjpuX2Rpc3RpbmN0KHBsb3RfZGYkcGFydHlfc3VwcG9ydF9oKSAvIDMpKSwKICAgICAgZGV2aWNlID0gZ3JEZXZpY2VzOjpjYWlyb19wZGYsCiAgICAgIGJnID0gIndoaXRlIgogICAgKQogIH0gZWxzZSB7CiAgICBwX3JlbGF0aXZlX3N1cHBvcnQgPC0gTlVMTAogIH0KICAKICBsaXN0KAogICAgb2JzZXJ2ZWQgPSBvYnNlcnZlZF9kZiwKICAgIGludGVydmFscyA9IGludGVydmFsX2RmLAogICAgc2xvcGVzID0gc2xvcGVfZGYsCiAgICBmYWlsdXJlcyA9IGZhaWx1cmVzX2RmLAogICAgcGxvdCA9IHBfcmVsYXRpdmVfc3VwcG9ydAogICkKfQoKcGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWVfcmVzdWx0cyA8LSBwdXJycjo6bWFwMigKICBzdHVkeV9zcGVjcywKICBwYXJ0eV9zdXBwb3J0X2FtY2VfcmVzdWx0cywKICBydW5fc3VwcG9ydF9yZWxhdGl2ZV9jdWUKKQoKCiMg6KOc6YG6SemWoumAo+OCs+ODvOODiQpleHRyYWN0X2N1ZV9zbG9wZV9pbmZlcmVuY2UgPC0gZnVuY3Rpb24oc3R1ZHlfc3BlYykgewogIGVudiA8LSBzdHVkeV9zcGVjJGVudgogIAogIGVudiRyZWxhdGl2ZV9jdWVfc2xvcGVfaW5mZXJlbmNlICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgc3R1ZHlfaWQgPSBzdHVkeV9zcGVjJHN0dWR5X2lkLAogICAgICBzdHVkeV9sYWJlbCA9IHN0dWR5X3NwZWMkc3R1ZHlfbGFiZWwsCiAgICAgIC5iZWZvcmUgPSAxCiAgICApCn0KCmN1ZV9zbG9wZV9pbmZlcmVuY2VfYWxsIDwtIHB1cnJyOjptYXBfZGZyKAogIHN0dWR5X3NwZWNzLAogIGV4dHJhY3RfY3VlX3Nsb3BlX2luZmVyZW5jZQopICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBzdGF0aXN0aWNfbGFiZWwgPSBkcGx5cjo6cmVjb2RlKAogICAgICBzdGF0aXN0aWMsCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UgPSAi5pS/5YWa44Gu5omL44GM44GL44KK44Gu5pyq6Kq/5pW06YeN6KaB5bqmIiwKICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSA9ICLntYzmuIjjga7miYvjgYzjgYvjgorjga7mnKroqr/mlbTph43opoHluqYiLAogICAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAi5pS/5YWa44Gu5omL44GM44GL44KK44Gu6YG45oqe6IKi5pWw6Kq/5pW05riI44G/6YeN6KaB5bqmIiwKICAgICAgZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCA9CiAgICAgICAgIue1jOa4iOOBruaJi+OBjOOBi+OCiuOBrumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6piIsCiAgICAgIHJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSA9ICLmlL/lhZrjga7miYvjgYzjgYvjgorjga7nm7jlr77mr5Tph40iCiAgICApLAogICAgbWV0cmljX3NjYWxlID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgc3RhdGlzdGljICVpbiUgYygKICAgICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIsCiAgICAgICAgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQiCiAgICAgICkgfiAiY2hvaWNlX3NldF9hZGp1c3RlZF9iYXNlbGluZV9yZWxhdGl2ZSIsCiAgICAgIHN0YXRpc3RpYyA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIiB+CiAgICAgICAgInJlbGF0aXZlX3NoYXJlIiwKICAgICAgVFJVRSB+ICJ1bmFkanVzdGVkX3Byb2JhYmlsaXR5X2RpZmZlcmVuY2UiCiAgICApLAogICAgZXN0aW1hdGVfcHBfcGVyX29wdGlvbiA9IGVzdGltYXRlICogMTAwLAogICAgY29uZl9sb3dfcHBfcGVyX29wdGlvbiA9IGNvbmZfbG93ICogMTAwLAogICAgY29uZl9oaWdoX3BwX3Blcl9vcHRpb24gPSBjb25mX2hpZ2ggKiAxMDAKICApCgp3cml0ZV9jc3ZfdW5pZmllZCgKICBjdWVfc2xvcGVfaW5mZXJlbmNlX2FsbCwKICAiY3VlX2ltcG9ydGFuY2VfbGluZWFyX3Nsb3BlX2FsbF9zdHVkaWVzLmNzdiIKKQoKY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5IDwtIGN1ZV9zbG9wZV9pbmZlcmVuY2VfYWxsICU+JQogIGRwbHlyOjpmaWx0ZXIoCiAgICBzdGF0aXN0aWMgJWluJSBjKAogICAgICAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIsCiAgICAgICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIgogICAgKQogICkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGN1ZV9mYW1pbHkgPSBkcGx5cjo6cmVjb2RlKAogICAgICBzdGF0aXN0aWMsCiAgICAgIHBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2VfYWRqdXN0ZWQgPQogICAgICAgICLmlL/lhZrjg7vmlL/lhZrlkI3miYvjgYzjgYvjgooiLAogICAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0KICAgICAgICAi57WM5riI5omL44GM44GL44KKIgogICAgKSwKICAgIGVzdGltYXRlX2Jhc2VsaW5lX3BjdF9wZXJfb3B0aW9uID0gZXN0aW1hdGUgKiAxMDAsCiAgICBjb25mX2xvd19iYXNlbGluZV9wY3RfcGVyX29wdGlvbiA9IGNvbmZfbG93ICogMTAwLAogICAgY29uZl9oaWdoX2Jhc2VsaW5lX3BjdF9wZXJfb3B0aW9uID0gY29uZl9oaWdoICogMTAwCiAgKQoKd3JpdGVfY3N2X3VuaWZpZWQoCiAgY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5LAogICJjaG9pY2Vfc2V0X2FkanVzdGVkX2ltcG9ydGFuY2VfbGluZWFyX3Nsb3Blcy5jc3YiCikKCmh5cG90aGVzaXNfbWFwIDwtIHRpYmJsZTo6dHJpYmJsZSgKICB+c3R1ZHlfaWQsIH5oeXBvdGhlc2lzLCB+c3RhdGlzdGljLCB+ZXhwZWN0ZWRfZGlyZWN0aW9uLAogICJzdHVkeTEiLCAiSDFh77yI5a6f6aiTMe+8iSIsICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlIiwgInBvc2l0aXZlIiwKICAic3R1ZHkxIiwgIkgxYu+8iOWun+mokzHvvIkiLCAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZSIsICJuZWdhdGl2ZSIsCiAgInN0dWR5MiIsICJIMWHvvIjlrp/pqJMy77yJIiwgInBhcnR5X2ltcG9ydGFuY2VfcGFpcndpc2UiLCAicG9zaXRpdmUiLAogICJzdHVkeTIiLCAiSDFi77yI5a6f6aiTMu+8iSIsICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiwgIm5lZ2F0aXZlIiwKICAic3R1ZHkzIiwgIkgyYe+8iOWun+mokzPvvIkiLCAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsICJwb3NpdGl2ZSIsCiAgInN0dWR5MyIsICJIMmLvvIjlrp/pqJMz77yJIiwgImVjb25vbWljX2ltcG9ydGFuY2VfcGFpcndpc2UiLCAibmVnYXRpdmUiCikKCmh5cG90aGVzaXNfdGVzdF9zdW1tYXJ5IDwtIGh5cG90aGVzaXNfbWFwICU+JQogIGRwbHlyOjpsZWZ0X2pvaW4oCiAgICBjdWVfc2xvcGVfaW5mZXJlbmNlX2FsbCAlPiUKICAgICAgZHBseXI6OnNlbGVjdCgKICAgICAgICBzdHVkeV9pZCwKICAgICAgICBzdHVkeV9sYWJlbCwKICAgICAgICBzdGF0aXN0aWMsCiAgICAgICAgZXN0aW1hdGUsCiAgICAgICAgY29uZl9sb3csCiAgICAgICAgY29uZl9oaWdoLAogICAgICAgIHBfdmFsdWVfdHdvX3NpZGVkCiAgICAgICksCiAgICBieSA9IGMoInN0dWR5X2lkIiwgInN0YXRpc3RpYyIpCiAgKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgZXN0aW1hdGVfaW5fZXhwZWN0ZWRfZGlyZWN0aW9uID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgZXhwZWN0ZWRfZGlyZWN0aW9uID09ICJwb3NpdGl2ZSIgfiBlc3RpbWF0ZSA+IDAsCiAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA9PSAibmVnYXRpdmUiIH4gZXN0aW1hdGUgPCAwLAogICAgICBUUlVFIH4gTkEKICAgICksCiAgICBjaV9leGNsdWRlc196ZXJvX2luX2V4cGVjdGVkX2RpcmVjdGlvbiA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIGV4cGVjdGVkX2RpcmVjdGlvbiA9PSAicG9zaXRpdmUiIH4gY29uZl9sb3cgPiAwLAogICAgICBleHBlY3RlZF9kaXJlY3Rpb24gPT0gIm5lZ2F0aXZlIiB+IGNvbmZfaGlnaCA8IDAsCiAgICAgIFRSVUUgfiBOQQogICAgKSwKICAgIGNvbmNsdXNpb24gPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBjaV9leGNsdWRlc196ZXJvX2luX2V4cGVjdGVkX2RpcmVjdGlvbiB+CiAgICAgICAgIuS6iOa4rOaWueWQkeOBpzk1JeS/oemgvOWMuumWk+OBjDDjgpLlkKvjgb7jgZrjgIHntbHoqIjnmoTjgavmlK/mjIEiLAogICAgICBlc3RpbWF0ZV9pbl9leHBlY3RlZF9kaXJlY3Rpb24gfgogICAgICAgICLngrnmjqjlrprjga/kuojmuKzmlrnlkJHjgaDjgYzjgIE5NSXkv6HpoLzljLrplpPjgYww44KS5ZCr44KAIiwKICAgICAgVFJVRSB+CiAgICAgICAgIueCueaOqOWumuOBjOS6iOa4rOaWueWQkeOBqOS4gOiHtOOBl+OBquOBhCIKICAgICksCiAgICBlc3RpbWF0ZV9wcF9wZXJfb3B0aW9uID0gZXN0aW1hdGUgKiAxMDAsCiAgICBjb25mX2xvd19wcF9wZXJfb3B0aW9uID0gY29uZl9sb3cgKiAxMDAsCiAgICBjb25mX2hpZ2hfcHBfcGVyX29wdGlvbiA9IGNvbmZfaGlnaCAqIDEwMCwKICAgIGh5cG90aGVzaXMgPSBmYWN0b3IoCiAgICAgIGh5cG90aGVzaXMsCiAgICAgIGxldmVscyA9IHJldihoeXBvdGhlc2lzX21hcCRoeXBvdGhlc2lzKQogICAgKQogICkKCndyaXRlX2Nzdl91bmlmaWVkKAogIGh5cG90aGVzaXNfdGVzdF9zdW1tYXJ5LAogICJtYWluX2h5cG90aGVzaXNfbGluZWFyX3RyZW5kX3Rlc3RzLmNzdiIKKQoKcF9oeXBvdGhlc2lzX3Nsb3BlcyA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgaHlwb3RoZXNpc190ZXN0X3N1bW1hcnksCiAgZ2dwbG90Mjo6YWVzKAogICAgeCA9IGVzdGltYXRlX3BwX3Blcl9vcHRpb24sCiAgICB5ID0gaHlwb3RoZXNpcywKICAgIHNoYXBlID0gZXhwZWN0ZWRfZGlyZWN0aW9uCiAgKQopICsKICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IDAsCiAgICBsaW5ld2lkdGggPSAwLjQ1CiAgKSArCiAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcmgoCiAgICBnZ3Bsb3QyOjphZXMoCiAgICAgIHhtaW4gPSBjb25mX2xvd19wcF9wZXJfb3B0aW9uLAogICAgICB4bWF4ID0gY29uZl9oaWdoX3BwX3Blcl9vcHRpb24KICAgICksCiAgICBoZWlnaHQgPSAwLjEyLAogICAgbGluZXdpZHRoID0gMC42MAogICkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICBzaXplID0gMi43LAogICAgZmlsbCA9ICJ3aGl0ZSIKICApICsKICBnZ3Bsb3QyOjpzY2FsZV9zaGFwZV9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKAogICAgICBwb3NpdGl2ZSA9IDIxLAogICAgICBuZWdhdGl2ZSA9IDI0CiAgICApLAogICAgbGFiZWxzID0gYygKICAgICAgcG9zaXRpdmUgPSAi5q2j44Gu5YK+5ZCR44KS5LqI5risIiwKICAgICAgbmVnYXRpdmUgPSAi6LKg44Gu5YK+5ZCR44KS5LqI5risIgogICAgKQogICkgKwogIGdncGxvdDI6OmxhYnMoCiAgICB4ID0gIumBuOaKnuiCouOBjDHjgaTlopfjgYjjgovjgajjgY3jga7ph43opoHluqbjga7lpInljJbvvIhwcO+8iSIsCiAgICB5ID0gTlVMTCwKICAgIHNoYXBlID0gTlVMTCwKICAgIGNhcHRpb24gPSBwYXN0ZTAoCiAgICAgICLph43opoHluqbjga/jgIHlkIzkuIDlsZ7mgKflhoXjga7lhajmsLTmupbjg5rjgqLjgavjgaTjgYTjgabpmZDnlYzlubPlnYfjga7ntbblr77lt67jgpLmsYLjgoHjgIEiLAogICAgICAi44Gd44Gu5bmz5Z2H44Go44GX44Gm566X5Ye644CC5qiq57ea44Gv5Zue562U6ICF44Kv44Op44K544K/44O744OW44O844OI44K544OI44Op44OD44OXOTUl5L+h6aC85Yy66ZaT44CCIgogICAgKQogICkgKwogIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDExKSArCiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKQogICkKCnNhdmVfcGxvdF9ib3RoKAogICJmaWdfc3VwcF9oeXBvdGhlc2lzX2xpbmVhcl90cmVuZF90ZXN0cyIsCiAgcF9oeXBvdGhlc2lzX3Nsb3BlcywKICB3aWR0aCA9IDkuNSwKICBoZWlnaHQgPSA1LjgKKQoKY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5IDwtIGNob2ljZV9zZXRfYWRqdXN0ZWRfc2xvcGVfc3VtbWFyeSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgc3R1ZHlfY3VlX2xhYmVsID0gcGFzdGUwKAogICAgICBzdHVkeV9sYWJlbCwKICAgICAgIu+8miIsCiAgICAgIGN1ZV9mYW1pbHkKICAgICksCiAgICBzdHVkeV9jdWVfbGFiZWwgPSBmYWN0b3IoCiAgICAgIHN0dWR5X2N1ZV9sYWJlbCwKICAgICAgbGV2ZWxzID0gcmV2KAogICAgICAgIHVuaXF1ZShzdHVkeV9jdWVfbGFiZWwpCiAgICAgICkKICAgICkKICApCgpwX2Nob2ljZV9zZXRfYWRqdXN0ZWRfc2xvcGVzIDwtIGdncGxvdDI6OmdncGxvdCgKICBjaG9pY2Vfc2V0X2FkanVzdGVkX3Nsb3BlX3N1bW1hcnksCiAgZ2dwbG90Mjo6YWVzKAogICAgeCA9IGVzdGltYXRlX2Jhc2VsaW5lX3BjdF9wZXJfb3B0aW9uLAogICAgeSA9IHN0dWR5X2N1ZV9sYWJlbCwKICAgIHNoYXBlID0gY3VlX2ZhbWlseQogICkKKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSgKICAgIHhpbnRlcmNlcHQgPSAwLAogICAgbGluZXdpZHRoID0gMC40NQogICkgKwogIGdncGxvdDI6Omdlb21fZXJyb3JiYXJoKAogICAgZ2dwbG90Mjo6YWVzKAogICAgICB4bWluID0gY29uZl9sb3dfYmFzZWxpbmVfcGN0X3Blcl9vcHRpb24sCiAgICAgIHhtYXggPSBjb25mX2hpZ2hfYmFzZWxpbmVfcGN0X3Blcl9vcHRpb24KICAgICksCiAgICBoZWlnaHQgPSAwLjEyLAogICAgbGluZXdpZHRoID0gMC42MAogICkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICBzaXplID0gMi43LAogICAgZmlsbCA9ICJ3aGl0ZSIKICApICsKICBnZ3Bsb3QyOjpzY2FsZV9zaGFwZV9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKAogICAgICAi5pS/5YWa44O75pS/5YWa5ZCN5omL44GM44GL44KKIiA9IDIxLAogICAgICAi57WM5riI5omL44GM44GL44KKIiA9IDI0CiAgICApCiAgKSArCiAgZ2dwbG90Mjo6bGFicygKICAgIHggPSBwYXN0ZTAoCiAgICAgICLpgbjmip7ogqLjgYwx44Gk5aKX44GI44KL44Go44GN44Gu6Kq/5pW05riI44G/6YeN6KaB5bqm44Gu5aSJ5YyWIiwKICAgICAgIu+8iOW5s+Wdh+mBuOaKnueiuueOh+OBq+WvvuOBmeOCi+WJsuWQiO+8mnBw77yJIgogICAgKSwKICAgIHkgPSBOVUxMLAogICAgc2hhcGUgPSBOVUxMLAogICAgY2FwdGlvbiA9IHBhc3RlMCgKICAgICAgIuiqv+aVtOa4iOOBv+mHjeimgeW6piA9IOacquiqv+aVtOmHjeimgeW6piDDt++8iDHvvI/pgbjmip7ogqLmlbDvvInjgIIiLAogICAgICAi5LqL5YmN55m76Yyy5riI44G/5Luu6Kqs44Gu5Yik5a6a44Gn44Gv44Gq44GP44CB6KiY6L+w55qE44O75oSf5bqm5YiG5p6Q44Go44GX44Gm56S644GZ44CCIgogICAgKQogICkgKwogIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDExKSArCiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKQogICkKCnNhdmVfcGxvdF9ib3RoKAogICJmaWdfc3VwcF9jaG9pY2Vfc2V0X2FkanVzdGVkX2ltcG9ydGFuY2Vfc2xvcGVzIiwKICBwX2Nob2ljZV9zZXRfYWRqdXN0ZWRfc2xvcGVzLAogIHdpZHRoID0gMTAuNSwKICBoZWlnaHQgPSA2LjIKKQoKCiMg5pys5paH44Kz44O844OJCnJ1bl9zdHVkeTNfYWxsX3BhcnR5X21hdGNoIDwtIGZ1bmN0aW9uKCkgewogIGVudiA8LSBzdHVkeTNfZW52CiAgb3V0X2RpciA8LSBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkzX3BhcnR5X21hdGNoX2FsbF9wYXJ0aWVzIikKICBkaXIuY3JlYXRlKG91dF9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQogIAogIGRhdCA8LSBlbnYkY29uam9pbnRfbWF0Y2ggJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCiAgICAgIHBhcnR5X24gPSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihwYXJ0eV9uKSksCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgPSBhcy5jaGFyYWN0ZXIoc3VwcG9ydF9wYXJ0eV92YWxpZCkKICAgICkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICAhaXMubmEoc3VwcG9ydF9wYXJ0eV92YWxpZCksCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgIT0gIiIKICAgICkKICAKICBzdXBwb3J0X2NlbGxfY291bnRzIDwtIGRhdCAlPiUKICAgIGRwbHlyOjpkaXN0aW5jdChJRCwgc3VwcG9ydF9wYXJ0eV92YWxpZCwgcGFydHlfbikgJT4lCiAgICBkcGx5cjo6Y291bnQoCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICAgIHBhcnR5X24sCiAgICAgIG5hbWUgPSAibl9yZXNwb25kZW50cyIKICAgICkgJT4lCiAgICB0aWR5cjo6Y29tcGxldGUoCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICAgIHBhcnR5X24gPSAyOjUsCiAgICAgIGZpbGwgPSBsaXN0KG5fcmVzcG9uZGVudHMgPSAwTCkKICAgICkgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoc3VwcG9ydF9wYXJ0eV92YWxpZCkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBuX3RvdGFsID0gc3VtKG5fcmVzcG9uZGVudHMpLAogICAgICBtaW5fY2VsbF9uID0gbWluKG5fcmVzcG9uZGVudHMpLAogICAgICBhbGxfZm91cl9jb25kaXRpb25zID0gYWxsKG5fcmVzcG9uZGVudHMgPiAwKQogICAgKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkKICAKICBlbGlnaWJsZV9wYXJ0aWVzIDwtIHN1cHBvcnRfY2VsbF9jb3VudHMgJT4lCiAgICBkcGx5cjo6ZGlzdGluY3QoCiAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICAgIG5fdG90YWwsCiAgICAgIG1pbl9jZWxsX24sCiAgICAgIGFsbF9mb3VyX2NvbmRpdGlvbnMKICAgICkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICBuX3RvdGFsID49IHVuaWZpZWRfY29uZmlnJG1pbl9zdXBwb3J0X3RvdGFsX24sCiAgICAgIG1pbl9jZWxsX24gPj0gdW5pZmllZF9jb25maWckbWluX3N1cHBvcnRfY2VsbF9uLAogICAgICBhbGxfZm91cl9jb25kaXRpb25zCiAgICApICU+JQogICAgZHBseXI6OmFycmFuZ2UoZHBseXI6OmRlc2Mobl90b3RhbCkpICU+JQogICAgZHBseXI6OnB1bGwoc3VwcG9ydF9wYXJ0eV92YWxpZCkKICAKICByZWFkcjo6d3JpdGVfY3N2KAogICAgc3VwcG9ydF9jZWxsX2NvdW50cywKICAgIGZpbGUucGF0aChvdXRfZGlyLCAicGFydHlfbWF0Y2hfYWxsX3BhcnR5X3NhbXBsZV9jb3VudHMuY3N2IiksCiAgICBuYSA9ICIiCiAgKQogIAogIGZvcm11bGFfY2VsbCA8LSBzdGF0czo6YXMuZm9ybXVsYSgKICAgIHBhc3RlKAogICAgICAic2VsZWN0ZWQgfiIsCiAgICAgIHBhc3RlKAogICAgICAgIGMoCiAgICAgICAgICAicGFydHlfbWF0Y2giLAogICAgICAgICAgZW52JGVjb25vbWljX2F0dHJfdGVybXMKICAgICAgICApLAogICAgICAgIGNvbGxhcHNlID0gIiArICIKICAgICAgKQogICAgKQogICkKICAKICBlc3RpbWF0ZV9jZWxsIDwtIGZ1bmN0aW9uKGdyb3VwX3ZhbHVlLCBuX3ZhbHVlKSB7CiAgICBkYXRfY2VsbCA8LSBkYXQgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoCiAgICAgICAgc3VwcG9ydF9wYXJ0eV92YWxpZCA9PSBncm91cF92YWx1ZSwKICAgICAgICBwYXJ0eV9uID09IG5fdmFsdWUKICAgICAgKQogICAgCiAgICBuX2lkcyA8LSBkcGx5cjo6bl9kaXN0aW5jdChkYXRfY2VsbCRJRCkKICAgIAogICAgaWYgKG5faWRzIDwgdW5pZmllZF9jb25maWckbWluX3N1cHBvcnRfY2VsbF9uKSB7CiAgICAgIHJldHVybigKICAgICAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgPSBncm91cF92YWx1ZSwKICAgICAgICAgIHBhcnR5X24gPSBuX3ZhbHVlLAogICAgICAgICAgbl9pZHMgPSBuX2lkcywKICAgICAgICAgIGVzdGltYXRlID0gTkFfcmVhbF8sCiAgICAgICAgICBzdGQuZXJyb3IgPSBOQV9yZWFsXywKICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICBjb25mLmhpZ2ggPSBOQV9yZWFsXywKICAgICAgICAgIHAudmFsdWUgPSBOQV9yZWFsXywKICAgICAgICAgIHN0YXR1cyA9ICJpbnN1ZmZpY2llbnRfY2VsbF9uIgogICAgICAgICkKICAgICAgKQogICAgfQogICAgCiAgICBtb2RlbCA8LSB0cnlDYXRjaCgKICAgICAgZml4ZXN0OjpmZW9scygKICAgICAgICBmb3JtdWxhX2NlbGwsCiAgICAgICAgZGF0YSA9IGRhdF9jZWxsLAogICAgICAgIHZjb3YgPSB+IElECiAgICAgICksCiAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgZQogICAgKQogICAgCiAgICBpZiAoaW5oZXJpdHMobW9kZWwsICJlcnJvciIpKSB7CiAgICAgIHJldHVybigKICAgICAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgPSBncm91cF92YWx1ZSwKICAgICAgICAgIHBhcnR5X24gPSBuX3ZhbHVlLAogICAgICAgICAgbl9pZHMgPSBuX2lkcywKICAgICAgICAgIGVzdGltYXRlID0gTkFfcmVhbF8sCiAgICAgICAgICBzdGQuZXJyb3IgPSBOQV9yZWFsXywKICAgICAgICAgIGNvbmYubG93ID0gTkFfcmVhbF8sCiAgICAgICAgICBjb25mLmhpZ2ggPSBOQV9yZWFsXywKICAgICAgICAgIHAudmFsdWUgPSBOQV9yZWFsXywKICAgICAgICAgIHN0YXR1cyA9IHBhc3RlMCgibW9kZWxfZXJyb3I6ICIsIGNvbmRpdGlvbk1lc3NhZ2UobW9kZWwpKQogICAgICAgICkKICAgICAgKQogICAgfQogICAgCiAgICB0aWR5X2ZpeGVzdF91bmlmaWVkKG1vZGVsKSAlPiUKICAgICAgZHBseXI6OmZpbHRlcih0ZXJtID09ICJwYXJ0eV9tYXRjaCIpICU+JQogICAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgPSBncm91cF92YWx1ZSwKICAgICAgICBwYXJ0eV9uID0gbl92YWx1ZSwKICAgICAgICBuX2lkcyA9IG5faWRzLAogICAgICAgIGVzdGltYXRlLAogICAgICAgIHN0ZC5lcnJvciwKICAgICAgICBjb25mLmxvdywKICAgICAgICBjb25mLmhpZ2gsCiAgICAgICAgcC52YWx1ZSwKICAgICAgICBzdGF0dXMgPSAiZXN0aW1hdGVkIgogICAgICApCiAgfQogIAogIGNlbGxfY29lZmZpY2llbnRzIDwtIHB1cnJyOjptYXBfZGZyKAogICAgZWxpZ2libGVfcGFydGllcywKICAgIGZ1bmN0aW9uKGdyb3VwX3ZhbHVlKSB7CiAgICAgIHB1cnJyOjptYXBfZGZyKAogICAgICAgIDI6NSwKICAgICAgICB+IGVzdGltYXRlX2NlbGwoZ3JvdXBfdmFsdWUsIC54KQogICAgICApCiAgICB9CiAgKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIGVzdGltYXRlX3BwID0gZXN0aW1hdGUgKiAxMDAsCiAgICAgIGNvbmYubG93X3BwID0gY29uZi5sb3cgKiAxMDAsCiAgICAgIGNvbmYuaGlnaF9wcCA9IGNvbmYuaGlnaCAqIDEwMCwKICAgICAgcGFydHlfbl9sYWJlbCA9IGZhY3RvcigKICAgICAgICBwYXJ0eV9uLAogICAgICAgIGxldmVscyA9IDI6NSwKICAgICAgICBsYWJlbHMgPSBwYXN0ZTAoMjo1LCAi6YG45oqe6IKiIikKICAgICAgKSwKICAgICAgbWFpbl90ZXh0X3BhcnR5ID0gc3VwcG9ydF9wYXJ0eV92YWxpZCAlaW4lIGMoCiAgICAgICAgIuiHqueUseawkeS4u+WFmiIsCiAgICAgICAgIuS4remBk+aUuemdqemAo+WQiCIsCiAgICAgICAgIueri+aGsuawkeS4u+WFmiIsCiAgICAgICAgIuWPguaUv+WFmiIKICAgICAgKQogICAgKQogIAogIHJlYWRyOjp3cml0ZV9jc3YoCiAgICBjZWxsX2NvZWZmaWNpZW50cywKICAgIGZpbGUucGF0aChvdXRfZGlyLCAicGFydHlfbWF0Y2hfYWxsX3BhcnR5X2NvZWZmaWNpZW50cy5jc3YiKSwKICAgIG5hID0gIiIKICApCiAgCiAgZXN0aW1hdGVfdHJlbmQgPC0gZnVuY3Rpb24oZ3JvdXBfdmFsdWUpIHsKICAgIGRhdF9ncm91cCA8LSBkYXQgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoc3VwcG9ydF9wYXJ0eV92YWxpZCA9PSBncm91cF92YWx1ZSkgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgcGFydHlfbl9mX2hldGVyb2dlbmVpdHkgPSBmYWN0b3IoCiAgICAgICAgICBwYXJ0eV9uLAogICAgICAgICAgbGV2ZWxzID0gMjo1CiAgICAgICAgKSwKICAgICAgICBwYXJ0eV9uX2NfaGV0ZXJvZ2VuZWl0eSA9IHBhcnR5X24gLSAyCiAgICAgICkKICAgIAogICAgZm9ybXVsYV90cmVuZCA8LSBzdGF0czo6YXMuZm9ybXVsYSgKICAgICAgcGFzdGUoCiAgICAgICAgInNlbGVjdGVkIH4gcGFydHlfbl9mX2hldGVyb2dlbmVpdHkgKyBwYXJ0eV9tYXRjaCArIiwKICAgICAgICAicGFydHlfbWF0Y2g6cGFydHlfbl9jX2hldGVyb2dlbmVpdHkgKyIsCiAgICAgICAgcGFzdGUoZW52JGVjb25vbWljX2F0dHJfdGVybXMsIGNvbGxhcHNlID0gIiArICIpCiAgICAgICkKICAgICkKICAgIAogICAgbW9kZWwgPC0gdHJ5Q2F0Y2goCiAgICAgIGZpeGVzdDo6ZmVvbHMoCiAgICAgICAgZm9ybXVsYV90cmVuZCwKICAgICAgICBkYXRhID0gZGF0X2dyb3VwLAogICAgICAgIHZjb3YgPSB+IElECiAgICAgICksCiAgICAgIGVycm9yID0gZnVuY3Rpb24oZSkgZQogICAgKQogICAgCiAgICBpZiAoaW5oZXJpdHMobW9kZWwsICJlcnJvciIpKSB7CiAgICAgIHJldHVybigKICAgICAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQgPSBncm91cF92YWx1ZSwKICAgICAgICAgIHRlcm0gPSAicGFydHlfbWF0Y2g6cGFydHlfbl9jX2hldGVyb2dlbmVpdHkiLAogICAgICAgICAgZXN0aW1hdGUgPSBOQV9yZWFsXywKICAgICAgICAgIHN0ZC5lcnJvciA9IE5BX3JlYWxfLAogICAgICAgICAgY29uZi5sb3cgPSBOQV9yZWFsXywKICAgICAgICAgIGNvbmYuaGlnaCA9IE5BX3JlYWxfLAogICAgICAgICAgcC52YWx1ZSA9IE5BX3JlYWxfLAogICAgICAgICAgc3RhdHVzID0gcGFzdGUwKCJtb2RlbF9lcnJvcjogIiwgY29uZGl0aW9uTWVzc2FnZShtb2RlbCkpCiAgICAgICAgKQogICAgICApCiAgICB9CiAgICAKICAgIHRpZHlfZml4ZXN0X3VuaWZpZWQobW9kZWwpICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKAogICAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QoCiAgICAgICAgICB0ZXJtLAogICAgICAgICAgInBhcnR5X21hdGNoOnBhcnR5X25fY19oZXRlcm9nZW5laXR5fHBhcnR5X25fY19oZXRlcm9nZW5laXR5OnBhcnR5X21hdGNoIgogICAgICAgICkKICAgICAgKSAlPiUKICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkID0gZ3JvdXBfdmFsdWUsCiAgICAgICAgc3RhdHVzID0gImVzdGltYXRlZCIsCiAgICAgICAgLmJlZm9yZSA9IDEKICAgICAgKQogIH0KICAKICB0cmVuZF9jb2VmZmljaWVudHMgPC0gcHVycnI6Om1hcF9kZnIoCiAgICBlbGlnaWJsZV9wYXJ0aWVzLAogICAgZXN0aW1hdGVfdHJlbmQKICApICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgZXN0aW1hdGVfcHBfcGVyX29wdGlvbiA9IGVzdGltYXRlICogMTAwLAogICAgICBjb25mLmxvd19wcF9wZXJfb3B0aW9uID0gY29uZi5sb3cgKiAxMDAsCiAgICAgIGNvbmYuaGlnaF9wcF9wZXJfb3B0aW9uID0gY29uZi5oaWdoICogMTAwCiAgICApCiAgCiAgcmVhZHI6OndyaXRlX2NzdigKICAgIHRyZW5kX2NvZWZmaWNpZW50cywKICAgIGZpbGUucGF0aChvdXRfZGlyLCAicGFydHlfbWF0Y2hfYWxsX3BhcnR5X2xpbmVhcl90cmVuZHMuY3N2IiksCiAgICBuYSA9ICIiCiAgKQogIAogIHBsb3RfZGYgPC0gY2VsbF9jb2VmZmljaWVudHMgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICBzdGF0dXMgPT0gImVzdGltYXRlZCIsCiAgICAgIGlzLmZpbml0ZShlc3RpbWF0ZV9wcCkKICAgICkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBzdXBwb3J0X3BhcnR5X3ZhbGlkID0gZmFjdG9yKAogICAgICAgIHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICAgICAgbGV2ZWxzID0gZWxpZ2libGVfcGFydGllcwogICAgICApCiAgICApCiAgCiAgaWYgKG5yb3cocGxvdF9kZikgPiAwKSB7CiAgICBwX2FsbF9wYXJ0eV9tYXRjaCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgICAgIHBsb3RfZGYsCiAgICAgIGdncGxvdDI6OmFlcygKICAgICAgICB4ID0gcGFydHlfbiwKICAgICAgICB5ID0gZXN0aW1hdGVfcHAsCiAgICAgICAgZ3JvdXAgPSAxCiAgICAgICkKICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKAogICAgICAgIHlpbnRlcmNlcHQgPSAwLAogICAgICAgIGxpbmV3aWR0aCA9IDAuNDAKICAgICAgKSArCiAgICAgIGdncGxvdDI6Omdlb21fbGluZSgKICAgICAgICBsaW5ld2lkdGggPSAwLjY1CiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX2Vycm9yYmFyKAogICAgICAgIGdncGxvdDI6OmFlcygKICAgICAgICAgIHltaW4gPSBjb25mLmxvd19wcCwKICAgICAgICAgIHltYXggPSBjb25mLmhpZ2hfcHAKICAgICAgICApLAogICAgICAgIHdpZHRoID0gMC4wOCwKICAgICAgICBsaW5ld2lkdGggPSAwLjU1CiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjpnZW9tX3BvaW50KAogICAgICAgIHNoYXBlID0gMjEsCiAgICAgICAgZmlsbCA9ICJ3aGl0ZSIsCiAgICAgICAgc2l6ZSA9IDIuNAogICAgICApICsKICAgICAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCgKICAgICAgICB+IHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICAgICAgbmNvbCA9IDMKICAgICAgKSArCiAgICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cygKICAgICAgICBicmVha3MgPSAyOjUsCiAgICAgICAgbGFiZWxzID0gcGFzdGUwKDI6NSwgIumBuOaKnuiCoiIpCiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjpsYWJzKAogICAgICAgIHggPSAi5o+Q56S644GV44KM44KL6YG45oqe6IKi5pWwIiwKICAgICAgICB5ID0gIuaUr+aMgeaUv+WFmuOBqOaPkOekuuaUv+WFmuWQjeOBruS4gOiHtOWKueaenO+8iHBw77yJIiwKICAgICAgICBjYXB0aW9uID0gcGFzdGUwKAogICAgICAgICAgIuWQhOaUr+aMgeaUv+WFmuOCteODluOCsOODq+ODvOODl+WGheOBpyBzZWxlY3RlZCB+IHBhcnR5X21hdGNoICsg57WM5riI5bGe5oCn44KS5o6o5a6a44CCIiwKICAgICAgICAgICLmqJnmupboqqTlt67jga/lm57nrZTogIVJROOBp+OCr+ODqeOCueOCv+WMluOAgiIKICAgICAgICApCiAgICAgICkgKwogICAgICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMC41KSArCiAgICAgIGdncGxvdDI6OnRoZW1lKAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGdncGxvdDI6OmVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKQogICAgICApCiAgICAKICAgIGdncGxvdDI6Omdnc2F2ZSgKICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X21hdGNoX2FsbF9wYXJ0aWVzLnBuZyIpLAogICAgICBwbG90ID0gcF9hbGxfcGFydHlfbWF0Y2gsCiAgICAgIHdpZHRoID0gMTEuNSwKICAgICAgaGVpZ2h0ID0gbWF4KAogICAgICAgIDcuMCwKICAgICAgICAyLjcgKiBjZWlsaW5nKGxlbmd0aChlbGlnaWJsZV9wYXJ0aWVzKSAvIDMpCiAgICAgICksCiAgICAgIGRwaSA9IDQwMCwKICAgICAgYmcgPSAid2hpdGUiCiAgICApCiAgICAKICAgIGdncGxvdDI6Omdnc2F2ZSgKICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0X2RpciwgInBhcnR5X21hdGNoX2FsbF9wYXJ0aWVzLnBkZiIpLAogICAgICBwbG90ID0gcF9hbGxfcGFydHlfbWF0Y2gsCiAgICAgIHdpZHRoID0gMTEuNSwKICAgICAgaGVpZ2h0ID0gbWF4KAogICAgICAgIDcuMCwKICAgICAgICAyLjcgKiBjZWlsaW5nKGxlbmd0aChlbGlnaWJsZV9wYXJ0aWVzKSAvIDMpCiAgICAgICksCiAgICAgIGRldmljZSA9IGdyRGV2aWNlczo6Y2Fpcm9fcGRmLAogICAgICBiZyA9ICJ3aGl0ZSIKICAgICkKICB9IGVsc2UgewogICAgcF9hbGxfcGFydHlfbWF0Y2ggPC0gTlVMTAogIH0KICAKICBsaXN0KAogICAgc2FtcGxlX2NvdW50cyA9IHN1cHBvcnRfY2VsbF9jb3VudHMsCiAgICBlbGlnaWJsZV9wYXJ0aWVzID0gZWxpZ2libGVfcGFydGllcywKICAgIGNvZWZmaWNpZW50cyA9IGNlbGxfY29lZmZpY2llbnRzLAogICAgdHJlbmRzID0gdHJlbmRfY29lZmZpY2llbnRzLAogICAgcGxvdCA9IHBfYWxsX3BhcnR5X21hdGNoCiAgKQp9CgpzdHVkeTNfYWxsX3BhcnR5X21hdGNoX3Jlc3VsdHMgPC0gcnVuX3N0dWR5M19hbGxfcGFydHlfbWF0Y2goKQoKCmV4dHJhY3RfY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfd2VpZ2h0IDwtIGZ1bmN0aW9uKHN0dWR5X3NwZWMpIHsKICBlbnYgPC0gc3R1ZHlfc3BlYyRlbnYKICAKICBlbnYkcmVsYXRpdmVfY3VlX2NvbmRpdGlvbl9pbnRlcnZhbHMgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICBzdGF0aXN0aWMgPT0gInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIKICAgICkgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBzdHVkeV9pZCA9IHN0dWR5X3NwZWMkc3R1ZHlfaWQsCiAgICAgIHN0dWR5X2xhYmVsID0gc3R1ZHlfc3BlYyRzdHVkeV9sYWJlbCwKICAgICAgcGFydHlfbiwKICAgICAgZXN0aW1hdGUsCiAgICAgIGNvbmZfbG93LAogICAgICBjb25mX2hpZ2gKICAgICkKfQoKY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfd2VpZ2h0IDwtIHB1cnJyOjptYXBfZGZyKAogIHN0dWR5X3NwZWNzLAogIGV4dHJhY3RfY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfd2VpZ2h0CikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIGVzdGltYXRlX3BjdCA9IGVzdGltYXRlICogMTAwLAogICAgY29uZl9sb3dfcGN0ID0gY29uZl9sb3cgKiAxMDAsCiAgICBjb25mX2hpZ2hfcGN0ID0gY29uZl9oaWdoICogMTAwLAogICAgc3R1ZHlfbGFiZWwgPSBmYWN0b3IoCiAgICAgIHN0dWR5X2xhYmVsLAogICAgICBsZXZlbHMgPSB2YXBwbHkoCiAgICAgICAgc3R1ZHlfc3BlY3MsCiAgICAgICAgYFtbYCwKICAgICAgICBjaGFyYWN0ZXIoMSksCiAgICAgICAgInN0dWR5X2xhYmVsIgogICAgICApCiAgICApCiAgKQoKd3JpdGVfY3N2X3VuaWZpZWQoCiAgY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfd2VpZ2h0LAogICJjcm9zc19zdHVkeV9yZWxhdGl2ZV9wYXJ0eV93ZWlnaHQuY3N2IgopCgpwX2Nyb3NzX3N0dWR5X3JlbGF0aXZlIDwtIGdncGxvdDI6OmdncGxvdCgKICBjcm9zc19zdHVkeV9yZWxhdGl2ZV93ZWlnaHQsCiAgZ2dwbG90Mjo6YWVzKAogICAgeCA9IHBhcnR5X24sCiAgICB5ID0gZXN0aW1hdGVfcGN0LAogICAgbGluZXR5cGUgPSBzdHVkeV9sYWJlbCwKICAgIHNoYXBlID0gc3R1ZHlfbGFiZWwsCiAgICBncm91cCA9IHN0dWR5X2xhYmVsCiAgKQopICsKICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKAogICAgeWludGVyY2VwdCA9IDUwLAogICAgbGluZXR5cGUgPSAiZG90dGVkIiwKICAgIGxpbmV3aWR0aCA9IDAuNDUKICApICsKICBnZ3Bsb3QyOjpnZW9tX2xpbmUoCiAgICBsaW5ld2lkdGggPSAwLjgwCiAgKSArCiAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcigKICAgIGdncGxvdDI6OmFlcygKICAgICAgeW1pbiA9IGNvbmZfbG93X3BjdCwKICAgICAgeW1heCA9IGNvbmZfaGlnaF9wY3QKICAgICksCiAgICB3aWR0aCA9IDAuMDcsCiAgICBsaW5ld2lkdGggPSAwLjYwLAogICAgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMDgpCiAgKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgIHNpemUgPSAyLjcsCiAgICBmaWxsID0gIndoaXRlIiwKICAgIHBvc2l0aW9uID0gZ2dwbG90Mjo6cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjA4KQogICkgKwogIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cygKICAgIGJyZWFrcyA9IDI6NSwKICAgIGxhYmVscyA9IHBhc3RlMCgyOjUsICLpgbjmip7ogqIiKQogICkgKwogIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cygKICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiJSIpLAogICAgYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSA2KQogICkgKwogIGdncGxvdDI6OmxhYnMoCiAgICB4ID0gIuaPkOekuuOBleOCjOOCi+mBuOaKnuiCouaVsCIsCiAgICB5ID0gIuaUv+WFmuOBruaJi+OBjOOBi+OCiuOBruebuOWvvuavlOmHjSIsCiAgICBsaW5ldHlwZSA9IE5VTEwsCiAgICBzaGFwZSA9IE5VTEwsCiAgICBjYXB0aW9uID0gcGFzdGUwKAogICAgICAi6ZmQ55WM5bmz5Z2H44Gu5bmz5Z2H57W25a++44Oa44Ki5beu44Gr5Z+644Gl44GP44CCIiwKICAgICAgIuOCqOODqeODvOODkOODvOOBr+WbnuetlOiAheOCr+ODqeOCueOCv+ODu+ODluODvOODiOOCueODiOODqeODg+ODlzk1JeS/oemgvOWMuumWk+OAgiIKICAgICkKICApICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMS41KSArCiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKQogICkKCnNhdmVfcGxvdF9ib3RoKAogICJmaWdfc3VwcF9jcm9zc19zdHVkeV9yZWxhdGl2ZV9wYXJ0eV93ZWlnaHQiLAogIHBfY3Jvc3Nfc3R1ZHlfcmVsYXRpdmUsCiAgd2lkdGggPSA5LjUsCiAgaGVpZ2h0ID0gNi4wCikKCgojIOWHuuWKm+aVtOeQhuOCs+ODvOODiQptYWluX3RleHRfZmlndXJlX21hbmlmZXN0IDwtIHRpYmJsZTo6dHJpYmJsZSgKICB+ZmlndXJlX251bWJlciwgfnN0dWR5LCB+YW5hbHlzaXMsIH5maWxlX3BuZywgfmZpbGVfcGRmLAogICJGaWd1cmUgNCIsICJTdHVkeSAxIiwgIuWFseWkiemHj+iqv+aVtOa4iOOBv0FNQ0UiLAogIGZpbGUucGF0aCh1bmlmaWVkX2NvbmZpZyRzdHVkeTEkb3V0cHV0X2RpciwgImFtY2VfY292X2ZhY2V0X21vZGVsLnBuZyIpLAogIE5BX2NoYXJhY3Rlcl8sCiAgIkZpZ3VyZSA1IiwgIlN0dWR5IDEiLCAi5pS/5YWa44O757WM5riI5omL44GM44GL44KK44Gu6YeN6KaB5bqm44Go55u45a++5q+U6YeNIiwKICBmaWxlLnBhdGgodW5pZmllZF9jb25maWckc3R1ZHkxJG91dHB1dF9kaXIsICJmaWdfc3R1ZHkxX3JlbGF0aXZlX2N1ZV93ZWlnaHRfanBfYncucG5nIiksCiAgZmlsZS5wYXRoKHVuaWZpZWRfY29uZmlnJHN0dWR5MSRvdXRwdXRfZGlyLCAiZmlnX3N0dWR5MV9yZWxhdGl2ZV9jdWVfd2VpZ2h0X2pwX2J3LnBkZiIpLAogICJGaWd1cmUgNiIsICJTdHVkeSAyIiwgIuWFseWkiemHj+iqv+aVtOa4iOOBv0FNQ0UiLAogIGZpbGUucGF0aCh1bmlmaWVkX2NvbmZpZyRzdHVkeTIkb3V0cHV0X2RpciwgImFtY2VfY292X2ZhY2V0X21vZGVsLnBuZyIpLAogIE5BX2NoYXJhY3Rlcl8sCiAgIkZpZ3VyZSA3IiwgIlN0dWR5IDIiLCAi5pS/5YWa44O757WM5riI5omL44GM44GL44KK44Gu6YeN6KaB5bqm44Go55u45a++5q+U6YeNIiwKICBmaWxlLnBhdGgodW5pZmllZF9jb25maWckc3R1ZHkyJG91dHB1dF9kaXIsICJmaWdfc3R1ZHkyX3JlbGF0aXZlX2N1ZV93ZWlnaHRfanBfYncucG5nIiksCiAgZmlsZS5wYXRoKHVuaWZpZWRfY29uZmlnJHN0dWR5MiRvdXRwdXRfZGlyLCAiZmlnX3N0dWR5Ml9yZWxhdGl2ZV9jdWVfd2VpZ2h0X2pwX2J3LnBkZiIpLAogICJGaWd1cmUgOCIsICJTdHVkeSAzIiwgIuWFseWkiemHj+iqv+aVtOa4iOOBv0FNQ0UiLAogIGZpbGUucGF0aCh1bmlmaWVkX2NvbmZpZyRzdHVkeTMkb3V0cHV0X2RpciwgImFtY2VfY292X2ZhY2V0X21vZGVsLnBuZyIpLAogIE5BX2NoYXJhY3Rlcl8sCiAgIkZpZ3VyZSA5IiwgIlN0dWR5IDMiLCAi5pS/5YWa5ZCN44O757WM5riI5omL44GM44GL44KK44Gu6YeN6KaB5bqm44Go55u45a++5q+U6YeNIiwKICBmaWxlLnBhdGgodW5pZmllZF9jb25maWckc3R1ZHkzJG91dHB1dF9kaXIsICJmaWdfc3R1ZHkzX3JlbGF0aXZlX2N1ZV93ZWlnaHRfanBfYncucG5nIiksCiAgZmlsZS5wYXRoKHVuaWZpZWRfY29uZmlnJHN0dWR5MyRvdXRwdXRfZGlyLCAiZmlnX3N0dWR5M19yZWxhdGl2ZV9jdWVfd2VpZ2h0X2pwX2J3LnBkZiIpLAogICJGaWd1cmUgMTAiLCAiU3R1ZHkgMyIsICLmlK/mjIHmlL/lhZrjgajmj5DnpLrmlL/lhZrlkI3jga7kuIDoh7TlirnmnpwiLAogIGZpbGUucGF0aCh1bmlmaWVkX2NvbmZpZyRzdHVkeTMkb3V0cHV0X2RpciwgInBhcnR5X21hdGNoX2VmZmVjdF9jb21iaW5lZC5wbmciKSwKICBOQV9jaGFyYWN0ZXJfCikKCndyaXRlX2Nzdl91bmlmaWVkKAogIG1haW5fdGV4dF9maWd1cmVfbWFuaWZlc3QsCiAgIm1haW5fdGV4dF9maWd1cmVfcmVwcm9kdWN0aW9uX21hbmlmZXN0LmNzdiIKKQoKc3VwcGxlbWVudF9maWd1cmVfbWFuaWZlc3QgPC0gdGliYmxlOjp0cmliYmxlKAogIH5zZWN0aW9uLCB+c3R1ZHksIH5hbmFseXNpcywgfmZpbGVfcG5nLAogICJCIiwgIlN0dWR5IDEiLCAi5Zue562U6ICF5Ymy5LuY44OQ44Op44Oz44K577yaTG92ZSBwbG90IiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkxX2Fzc2lnbm1lbnRfYmFsYW5jZV9sb3ZlX3Bsb3QucG5nIiksCiAgIkIiLCAiU3R1ZHkgMiIsICLlm57nrZTogIXlibLku5jjg5Djg6njg7PjgrnvvJpMb3ZlIHBsb3QiLAogIGZpbGUucGF0aCh1bmlmaWVkX291dHB1dF9kaXIsICJzdHVkeTJfYXNzaWdubWVudF9iYWxhbmNlX2xvdmVfcGxvdC5wbmciKSwKICAiQiIsICJTdHVkeSAzIiwgIuWbnuetlOiAheWJsuS7mOODkOODqeODs+OCue+8mkxvdmUgcGxvdCIsCiAgZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgInN0dWR5M19hc3NpZ25tZW50X2JhbGFuY2VfbG92ZV9wbG90LnBuZyIpLAogICJCIiwgIlN0dWR5IDEiLCAi5Zue562U6ICF5Ymy5LuY44OQ44Op44Oz44K577yaNDXluqbnt5roqLrmlq0iLAogIGZpbGUucGF0aCh1bmlmaWVkX291dHB1dF9kaXIsICJzdHVkeTFfYXNzaWdubWVudF9iYWxhbmNlX2RpYWdvbmFsX3Bsb3QucG5nIiksCiAgIkIiLCAiU3R1ZHkgMiIsICLlm57nrZTogIXlibLku5jjg5Djg6njg7PjgrnvvJo0NeW6pue3muiouuaWrSIsCiAgZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgInN0dWR5Ml9hc3NpZ25tZW50X2JhbGFuY2VfZGlhZ29uYWxfcGxvdC5wbmciKSwKICAiQiIsICJTdHVkeSAzIiwgIuWbnuetlOiAheWJsuS7mOODkOODqeODs+OCue+8mjQ15bqm57ea6Ki65patIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkzX2Fzc2lnbm1lbnRfYmFsYW5jZV9kaWFnb25hbF9wbG90LnBuZyIpLAogICJCIiwgIlN0dWR5IDEiLCAi5bGe5oCn5rC05rqW44Gu6Kaz5ris5q+U546H5a++5pyf5b6F5q+U546HIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkxX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9kaWFnb25hbF9wbG90LnBuZyIpLAogICJCIiwgIlN0dWR5IDIiLCAi5bGe5oCn5rC05rqW44Gu6Kaz5ris5q+U546H5a++5pyf5b6F5q+U546HIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkyX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9kaWFnb25hbF9wbG90LnBuZyIpLAogICJCIiwgIlN0dWR5IDMiLCAi5bGe5oCn5rC05rqW44Gu6Kaz5ris5q+U546H5a++5pyf5b6F5q+U546HIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAic3R1ZHkzX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9kaWFnb25hbF9wbG90LnBuZyIpLAogICJDIiwgIlN0dWR5IDHigJMzIiwgIkgxYS9IMWIvSDJhL0gyYuOBrue3muW9ouWCvuWQkeaknOWumiIsCiAgZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgImZpZ19zdXBwX2h5cG90aGVzaXNfbGluZWFyX3RyZW5kX3Rlc3RzLnBuZyIpLAogICJDIiwgIlN0dWR5IDHigJMzIiwgIumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puOBrue3muW9ouWCvuWQkSIsCiAgZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgImZpZ19zdXBwX2Nob2ljZV9zZXRfYWRqdXN0ZWRfaW1wb3J0YW5jZV9zbG9wZXMucG5nIiksCiAgIkMiLCAiU3R1ZHkgMSIsICLmnKroqr/mlbTjg7vpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqbjg7vnm7jlr77mr5Tph40iLAogIGZpbGUucGF0aCgKICAgIHVuaWZpZWRfY29uZmlnJHN0dWR5MSRvdXRwdXRfZGlyLAogICAgImZpZ19zdHVkeTFfcmVsYXRpdmVfY3VlX3dlaWdodF9jaG9pY2Vfc2V0X2FkanVzdGVkX2pwX2J3LnBuZyIKICApLAogICJDIiwgIlN0dWR5IDIiLCAi5pyq6Kq/5pW044O76YG45oqe6IKi5pWw6Kq/5pW05riI44G/6YeN6KaB5bqm44O755u45a++5q+U6YeNIiwKICBmaWxlLnBhdGgoCiAgICB1bmlmaWVkX2NvbmZpZyRzdHVkeTIkb3V0cHV0X2RpciwKICAgICJmaWdfc3R1ZHkyX3JlbGF0aXZlX2N1ZV93ZWlnaHRfY2hvaWNlX3NldF9hZGp1c3RlZF9qcF9idy5wbmciCiAgKSwKICAiQyIsICJTdHVkeSAzIiwgIuacquiqv+aVtOODu+mBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puODu+ebuOWvvuavlOmHjSIsCiAgZmlsZS5wYXRoKAogICAgdW5pZmllZF9jb25maWckc3R1ZHkzJG91dHB1dF9kaXIsCiAgICAiZmlnX3N0dWR5M19yZWxhdGl2ZV9jdWVfd2VpZ2h0X2Nob2ljZV9zZXRfYWRqdXN0ZWRfanBfYncucG5nIgogICksCiAgIkYiLCAiU3R1ZHkgMeKAkzMiLCAi5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeN44Gu5qiq5pat5q+U6LyDIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAiZmlnX3N1cHBfY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfcGFydHlfd2VpZ2h0LnBuZyIpLAogICJHIiwgIlN0dWR5IDMiLCAi5YWo44Gm44Gu5Y2B5YiG44Gq5qiZ5pys44KS44KC44Gk5pSv5oyB5pS/5YWa44Gu5LiA6Ie05Yq55p6cIiwKICBmaWxlLnBhdGgoCiAgICB1bmlmaWVkX291dHB1dF9kaXIsCiAgICAic3R1ZHkzX3BhcnR5X21hdGNoX2FsbF9wYXJ0aWVzIiwKICAgICJwYXJ0eV9tYXRjaF9hbGxfcGFydGllcy5wbmciCiAgKSwKICAiRyIsICJTdHVkeSAx4oCTMyIsICLmlK/mjIHmlL/lhZrliKVBTUNF44O755u45a++5q+U6YeNIiwKICBmaWxlLnBhdGgodW5pZmllZF9vdXRwdXRfZGlyLCAiPHN0dWR5Pl9wYXJ0eV9zdXBwb3J0IikKKQoKd3JpdGVfY3N2X3VuaWZpZWQoCiAgc3VwcGxlbWVudF9maWd1cmVfbWFuaWZlc3QsCiAgInN1cHBsZW1lbnRfZmlndXJlX21hbmlmZXN0LmNzdiIKKQoKc3VwcGxlbWVudF9zZWN0aW9uX21hbmlmZXN0IDwtIHRpYmJsZTo6dHJpYmJsZSgKICB+c2VjdGlvbiwgfnRpdGxlLCB+cGxhY2VtZW50X2xvZ2ljLCB+Y29yZV9vdXRwdXRzLAogICJBIiwgIuiqv+afu+ioreioiOODu+izquWVj+aWh+ODu+aomeacrOani+eviSIsCiAgIuiqreiAheOBjDPlrp/pqJPjga7nm7jpgZXjgajliIbmnpDlr77osaHogIXjga7lvaLmiJDjgpLlhYjjgavnorroqo3jgafjgY3jgovjgojjgYbjgavjgZnjgovjgIIiLAogICLoqr/mn7vjg5Xjg63jg7zjgIHlsZ7mgKfjg7vmsLTmupbjgIHos6rllY/mlofjgIFzYW1wbGVfZmxvd+OAgeadoeS7tuWIpW7jgIHmrKDmkI3pm4boqIgiLAogICJCIiwgIueEoeS9nOeCuuWJsuS7mOODu+WxnuaAp+aPkOekuuODu+ODh+ODvOOCv+WTgeizquOBruiouuaWrSIsCiAgIuaOqOWumue1kOaenOOCiOOCiuWJjeOBq+OAgeWHpue9ruadoeS7tuOBqOOCs+ODs+OCuOODp+OCpOODs+ODiOWxnuaAp+OBrueEoeS9nOeCuuWMluOBjOapn+iDveOBl+OBn+OBk+OBqOOCkuekuuOBmeOAgiIsCiAgIuadoeS7tuWIpeWFseWkiemHj+ihqOOAgeWFqDbmnaHku7bjg5rjgqLjga5TTUTjgIFMb3ZlIHBsb3TjgIE0NeW6pue3muWbs+OAgeWxnuaAp+awtOa6luOBruims+a4rOWvvuacn+W+heavlOeOhyIsCiAgIkMiLCAi5o6o5a6a6YeP44O755u45a++5q+U6YeN44O75Luu6Kqs5qSc5a6aIiwKICAi5pys5paH44Gu5byPKDEpKDIp44GoSDFhL0gxYi9IMmEvSDJi44Gu5Yik5a6a5pa55rOV44KS5LiA44GL5omA44Gr6ZuG57SE44GZ44KL44CCIiwKICBwYXN0ZTAoCiAgICAiQU1DReOAgemZkOeVjOW5s+Wdh+OAgeW5s+Wdh+e1tuWvvuODmuOCouW3ruOAgemBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puOAgSIsCiAgICAi55u45a++5q+U6YeN44CB44OW44O844OI44K544OI44Op44OD44OX44CB57ea5b2i5YK+5ZCR57Wx5ZCI6KGoIgogICksCiAgIkQiLCAi5a6f6aiTMe+8iDIwMjPlubTvvInjga7lrozlhajjgarntZDmnpwiLAogICLmnKzmloflm7M044O7NeOBruWGjeePvuW+jOOBq+OAgeijnOWKqeWIhuaekOOCkuWQjOOBmOWun+mok+WGheOBp+OBvuOBqOOCgeOCi+OAgiIsCiAgIuiqv+aVtOa4iOOBv+ODu+acquiqv+aVtEFNQ0XjgIHkuqTkupLkvZznlKjjgIHjg5Ljg7zjg4jjg57jg4Pjg5fjgIHmnaHku7bku5jjgY3jg63jgrjjg4Pjg4jjgIHnm7jlr77mr5Tph43lgr7lkJEiLAogICJFIiwgIuWun+mokzLvvIgyMDI25bm077yJ44GoMjAyM+KAkzIwMjblubTmr5TovIMiLAogICLlrp/pqJMx44Gu5YaN54++5oCn44Go5pmC54K56ZaT5aSJ5YyW44KS6YCj57aa44GX44Gm6Kqt44KB44KL44KI44GG44Gr44GZ44KL44CCIiwKICAi6Kq/5pW05riI44G/44O75pyq6Kq/5pW0QU1DReOAgeS6pOS6kuS9nOeUqOOAgeODkuODvOODiOODnuODg+ODl+OAgeadoeS7tuS7mOOBjeODreOCuOODg+ODiOOAgeebuOWvvuavlOmHjeWCvuWQkeOAgeaZgueCueavlOi8gyIsCiAgIkYiLCAi5a6f6aiTM++8iDIwMjblubTvvInjga7lrozlhajjgarntZDmnpwiLAogICLlhbfkvZPnmoTmlL/lhZrlkI3jga7liIbmnpDjgajjgIHmnKzmloflm7M444O7OeODuzEw44Gu6L+95Yqg5o6o5a6a44KS44G+44Go44KB44KL44CCIiwKICAiQU1DReOAgeOCq+ODhuOCtOODquOCq+ODq+ODu+e3muW9ouODiOODrOODs+ODieOAgeadoeS7tuS7mOOBjeODreOCuOODg+ODiOOAgeebuOWvvuavlOmHjeOAgeS4gOiHtOWKueaenCIsCiAgIkciLCAi5pS/5YWa5pSv5oyB44Gr44KI44KL55Ww6LOq5oCnIiwKICAi5pys5paH44Gu5YWa5rS+5oCn44Oh44Kr44OL44K644Og44Gr55u057WQ44GZ44KL44Gf44KB44CB6aCR5YGl5oCn5YiG5p6Q44GL44KJ54us56uL44GV44Gb44KL44CCIiwKICAi5pSv5oyB5pS/5YWa5YilQU1DReOAgeaUr+aMgeaUv+WFmsOX5bGe5oCnV2FsZOaknOWumuOAgeaUr+aMgeaUv+WFmuWIpeebuOWvvuavlOmHjeOAgeWFqOaUv+WFmuS4gOiHtOWKueaenCIsCiAgIkgiLCAi6Zmk5aSW5Z+65rqW44O75o6o5a6a5rOV44O75qiZ5pys5a6a576p44Gr6Zai44GZ44KL5oSf5bqm5YiG5p6QIiwKICAi5Li76KaB57WQ6KuW44GM5YiG5p6Q5LiK44Gu6YG45oqe44Gr5L6d5a2Y44GX44Gq44GE44GL44KS5pyA5b6M44Gr56K66KqN44GZ44KL44CCIiwKICAi5rOo5oSP44O75pON5L2c56K66KqN44CB5a6M5YWoNeiqsumhjOOAgeWFseWkiemHj+OBquOBl+OAgeadoeS7tuS7mOOBjeODreOCuOODg+ODiOOAgeS7o+abv+aomeacrCIsCiAgIkkiLCAi5YaN54++5oCn5oOF5aCxIiwKICAi5YWo44Gm44Gu5YiG5p6Q5b6M44Gr44CB5YaN54++44Gr5b+F6KaB44Gq5oqA6KGT5oOF5aCx44KS44G+44Go44KB44KL44CCIiwKICAi44OV44Kh44Kk44Or5LiA6Kan44CB5Lmx5pWw44K344O844OJ44CB44OW44O844OI44K544OI44Op44OD44OX5Zue5pWw44CB44OR44OD44Kx44O844K444CBc2Vzc2lvbkluZm8iCikKCndyaXRlX2Nzdl91bmlmaWVkKAogIHN1cHBsZW1lbnRfc2VjdGlvbl9tYW5pZmVzdCwKICAic3VwcGxlbWVudF9zZWN0aW9uX21hbmlmZXN0LmNzdiIKKQoKc2F2ZVJEUygKICBsaXN0KAogICAgY29uZmlnID0gdW5pZmllZF9jb25maWcsCiAgICBhc3NpZ25tZW50X2JhbGFuY2UgPSBhc3NpZ25tZW50X2JhbGFuY2VfcmVzdWx0cywKICAgIHByb2ZpbGVfcmFuZG9taXphdGlvbiA9IHByb2ZpbGVfcmFuZG9taXphdGlvbl9yZXN1bHRzLAogICAgY3VlX3Nsb3BlX2luZmVyZW5jZSA9IGN1ZV9zbG9wZV9pbmZlcmVuY2VfYWxsLAogICAgY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5ID0KICAgICAgY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5LAogICAgY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9wbG90ID0KICAgICAgcF9jaG9pY2Vfc2V0X2FkanVzdGVkX3Nsb3BlcywKICAgIGh5cG90aGVzaXNfdGVzdHMgPSBoeXBvdGhlc2lzX3Rlc3Rfc3VtbWFyeSwKICAgIHBhcnR5X3N1cHBvcnRfYW1jZSA9IHBhcnR5X3N1cHBvcnRfYW1jZV9yZXN1bHRzLAogICAgcGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWUgPSBwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV9yZXN1bHRzLAogICAgc3R1ZHkzX2FsbF9wYXJ0eV9tYXRjaCA9IHN0dWR5M19hbGxfcGFydHlfbWF0Y2hfcmVzdWx0cywKICAgIGNyb3NzX3N0dWR5X3JlbGF0aXZlX3dlaWdodCA9IGNyb3NzX3N0dWR5X3JlbGF0aXZlX3dlaWdodCwKICAgIGNyb3NzX3N0dWR5X3JlbGF0aXZlX3Bsb3QgPSBwX2Nyb3NzX3N0dWR5X3JlbGF0aXZlLAogICAgbWFpbl90ZXh0X2ZpZ3VyZV9tYW5pZmVzdCA9IG1haW5fdGV4dF9maWd1cmVfbWFuaWZlc3QsCiAgICBzdXBwbGVtZW50X2ZpZ3VyZV9tYW5pZmVzdCA9IHN1cHBsZW1lbnRfZmlndXJlX21hbmlmZXN0LAogICAgc3VwcGxlbWVudF9zZWN0aW9uX21hbmlmZXN0ID0gc3VwcGxlbWVudF9zZWN0aW9uX21hbmlmZXN0CiAgKSwKICBmaWxlID0gZmlsZS5wYXRoKAogICAgdW5pZmllZF9vdXRwdXRfZGlyLAogICAgInVuaWZpZWRfc3VwcGxlbWVudF9vYmplY3RzLnJkcyIKICApCikKCmNhcHR1cmUub3V0cHV0KAogIHNlc3Npb25JbmZvKCksCiAgZmlsZSA9IGZpbGUucGF0aCgKICAgIHVuaWZpZWRfb3V0cHV0X2RpciwKICAgICJzZXNzaW9uSW5mb191bmlmaWVkLnR4dCIKICApCikKCmNhdCgKICAiXG4z5a6f6aiT44Gu5pys5paH5Zuz5YaN54++44O76KOc6YG65YiG5p6Q44O75pSv5oyB5pS/5YWa5Yil55Ww6LOq5oCn5YiG5p6Q44GM5a6M5LqG44GX44G+44GX44Gf44CCXG4iLAogICLntbHlkIjlh7rlipvlhYg6ICIsCiAgbm9ybWFsaXplUGF0aCh1bmlmaWVkX291dHB1dF9kaXIpLAogICJcbiIsCiAgc2VwID0gIiIKKQoKCmZpbmFsX291dHB1dF9yb290IDwtIHVuaWZpZWRfY29uZmlnJG91dHB1dF9yb290CgpmaW5hbF9kaXJzIDwtIGxpc3QoCiAgbWFpbl9maWd1cmVzID0gZmlsZS5wYXRoKGZpbmFsX291dHB1dF9yb290LCAibWFpbl90ZXh0IiwgImZpZ3VyZXMiKSwKICBtYWluX3RhYmxlcyA9IGZpbGUucGF0aChmaW5hbF9vdXRwdXRfcm9vdCwgIm1haW5fdGV4dCIsICJ0YWJsZXMiKSwKICBzdXBwbGVtZW50X3Jvb3QgPSBmaWxlLnBhdGgoZmluYWxfb3V0cHV0X3Jvb3QsICJzdXBwbGVtZW50IiksCiAgc3VwcGxlbWVudF9jcm9zcyA9IGZpbGUucGF0aChmaW5hbF9vdXRwdXRfcm9vdCwgInN1cHBsZW1lbnQiLCAiY3Jvc3Nfc3R1ZHkiKSwKICBkaWFnbm9zdGljc19yb290ID0gZmlsZS5wYXRoKGZpbmFsX291dHB1dF9yb290LCAiZGlhZ25vc3RpY3MiKSwKICBtb2RlbF9vYmplY3RzX3Jvb3QgPSBmaWxlLnBhdGgoZmluYWxfb3V0cHV0X3Jvb3QsICJtb2RlbF9vYmplY3RzIiksCiAgbG9ncyA9IGZpbGUucGF0aChmaW5hbF9vdXRwdXRfcm9vdCwgImxvZ3MiKQopCgppbnZpc2libGUoCiAgbGFwcGx5KAogICAgZmluYWxfZGlycywKICAgIGRpci5jcmVhdGUsCiAgICBzaG93V2FybmluZ3MgPSBGQUxTRSwKICAgIHJlY3Vyc2l2ZSA9IFRSVUUKICApCikKCmZvciAoc3R1ZHlfaWQgaW4gbmFtZXMoc3R1ZHlfc3BlY3MpKSB7CiAgZm9yIChzdWJkaXIgaW4gYygiZmlndXJlcyIsICJ0YWJsZXNfY3N2IiwgInRhYmxlc190ZXgiKSkgewogICAgZGlyLmNyZWF0ZSgKICAgICAgZmlsZS5wYXRoKGZpbmFsX2RpcnMkc3VwcGxlbWVudF9yb290LCBzdHVkeV9pZCwgc3ViZGlyKSwKICAgICAgc2hvd1dhcm5pbmdzID0gRkFMU0UsCiAgICAgIHJlY3Vyc2l2ZSA9IFRSVUUKICAgICkKICB9CiAgZm9yIChzdWJkaXIgaW4gYygic2NyZWVuaW5nIiwgImJhbGFuY2UiLCAicmFuZG9taXphdGlvbiIpKSB7CiAgICBkaXIuY3JlYXRlKAogICAgICBmaWxlLnBhdGgoZmluYWxfZGlycyRkaWFnbm9zdGljc19yb290LCBzdHVkeV9pZCwgc3ViZGlyKSwKICAgICAgc2hvd1dhcm5pbmdzID0gRkFMU0UsCiAgICAgIHJlY3Vyc2l2ZSA9IFRSVUUKICAgICkKICB9CiAgZGlyLmNyZWF0ZSgKICAgIGZpbGUucGF0aChmaW5hbF9kaXJzJG1vZGVsX29iamVjdHNfcm9vdCwgc3R1ZHlfaWQpLAogICAgc2hvd1dhcm5pbmdzID0gRkFMU0UsCiAgICByZWN1cnNpdmUgPSBUUlVFCiAgKQp9Cgpmb3IgKHN1YmRpciBpbiBjKCJmaWd1cmVzIiwgInRhYmxlc19jc3YiLCAidGFibGVzX3RleCIpKSB7CiAgZGlyLmNyZWF0ZSgKICAgIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfY3Jvc3MsIHN1YmRpciksCiAgICBzaG93V2FybmluZ3MgPSBGQUxTRSwKICAgIHJlY3Vyc2l2ZSA9IFRSVUUKICApCn0KCgpjb3B5X2ZpbGVfaWZfZXhpc3RzIDwtIGZ1bmN0aW9uKHNvdXJjZSwgZGVzdGluYXRpb24pIHsKICBpZiAoaXMubmEoc291cmNlKSB8fCAhbnpjaGFyKHNvdXJjZSkgfHwgIWZpbGUuZXhpc3RzKHNvdXJjZSkpIHsKICAgIHJldHVybihGQUxTRSkKICB9CiAgZGlyLmNyZWF0ZShkaXJuYW1lKGRlc3RpbmF0aW9uKSwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCiAgaXNUUlVFKGZpbGUuY29weShzb3VyY2UsIGRlc3RpbmF0aW9uLCBvdmVyd3JpdGUgPSBUUlVFLCBjb3B5Lm1vZGUgPSBUUlVFKSkKfQoKY29weV9maWxlc19ieV9wYXR0ZXJuIDwtIGZ1bmN0aW9uKHNvdXJjZV9kaXIsIGRlc3RpbmF0aW9uX2RpciwgcGF0dGVybikgewogIGlmICghZGlyLmV4aXN0cyhzb3VyY2VfZGlyKSkgewogICAgcmV0dXJuKGNoYXJhY3RlcigpKQogIH0KICBmaWxlcyA8LSBsaXN0LmZpbGVzKAogICAgc291cmNlX2RpciwKICAgIHBhdHRlcm4gPSBwYXR0ZXJuLAogICAgZnVsbC5uYW1lcyA9IFRSVUUsCiAgICByZWN1cnNpdmUgPSBUUlVFLAogICAgaWdub3JlLmNhc2UgPSBUUlVFCiAgKQogIGlmIChsZW5ndGgoZmlsZXMpID09IDApIHsKICAgIHJldHVybihjaGFyYWN0ZXIoKSkKICB9CiAgZGlyLmNyZWF0ZShkZXN0aW5hdGlvbl9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQogIGRlc3RpbmF0aW9ucyA8LSBmaWxlLnBhdGgoZGVzdGluYXRpb25fZGlyLCBiYXNlbmFtZShmaWxlcykpCiAgY29waWVkIDwtIHZhcHBseSgKICAgIHNlcV9hbG9uZyhmaWxlcyksCiAgICBmdW5jdGlvbihpKSBjb3B5X2ZpbGVfaWZfZXhpc3RzKGZpbGVzW2ldLCBkZXN0aW5hdGlvbnNbaV0pLAogICAgbG9naWNhbCgxKQogICkKICBkZXN0aW5hdGlvbnNbY29waWVkXQp9CgpsYXRleF9lc2NhcGUgPC0gZnVuY3Rpb24oeCkgewogIHggPC0gYXMuY2hhcmFjdGVyKHgpCiAgeFtpcy5uYSh4KV0gPC0gIiIKCiAgZXNjYXBlX29uZSA8LSBmdW5jdGlvbihzKSB7CiAgICBjaGFycyA8LSBzdHJzcGxpdChzLCAiIiwgZml4ZWQgPSBUUlVFKVtbMV1dCgogICAgaWYgKGxlbmd0aChjaGFycykgPT0gMEwpIHsKICAgICAgcmV0dXJuKCIiKQogICAgfQoKICAgIHJlcGxhY2VtZW50IDwtIGMoCiAgICAgICJcXCIgPSAiXFx0ZXh0YmFja3NsYXNoe30iLAogICAgICAiJiIgID0gIlxcJiIsCiAgICAgICIlIiAgPSAiXFwlIiwKICAgICAgIiQiICA9ICJcXCQiLAogICAgICAiIyIgID0gIlxcIyIsCiAgICAgICJfIiAgPSAiXFxfIiwKICAgICAgInsiICA9ICJcXHsiLAogICAgICAifSIgID0gIlxcfSIsCiAgICAgICJ+IiAgPSAiXFx0ZXh0YXNjaWl0aWxkZXt9IiwKICAgICAgIl4iICA9ICJcXHRleHRhc2NpaWNpcmN1bXt9IgogICAgKQoKICAgIG91dCA8LSB2YXBwbHkoCiAgICAgIGNoYXJzLAogICAgICBmdW5jdGlvbihjaCkgewogICAgICAgIGlmIChjaCAlaW4lIG5hbWVzKHJlcGxhY2VtZW50KSkgewogICAgICAgICAgdW5uYW1lKHJlcGxhY2VtZW50W1tjaF1dKQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjaAogICAgICAgIH0KICAgICAgfSwKICAgICAgY2hhcmFjdGVyKDEpCiAgICApCgogICAgcGFzdGUwKG91dCwgY29sbGFwc2UgPSAiIikKICB9CgogIHZhcHBseSh4LCBlc2NhcGVfb25lLCBjaGFyYWN0ZXIoMSksIFVTRS5OQU1FUyA9IEZBTFNFKQp9Cgpmb3JtYXRfbnVtYmVyIDwtIGZ1bmN0aW9uKHgsIGRpZ2l0cyA9IDMpIHsKICBvdXQgPC0gaWZlbHNlKAogICAgaXMubmEoeCksCiAgICAiIiwKICAgIGZvcm1hdEMoeCwgZm9ybWF0ID0gImYiLCBkaWdpdHMgPSBkaWdpdHMpCiAgKQogIGFzLmNoYXJhY3RlcihvdXQpCn0KCmZvcm1hdF9pbnRlZ2VyIDwtIGZ1bmN0aW9uKHgpIHsKICBpZmVsc2UoaXMubmEoeCksICIiLCBzY2FsZXM6OmNvbW1hKGFzLmludGVnZXIocm91bmQoeCkpKSkKfQoKZm9ybWF0X3BfdmFsdWUgPC0gZnVuY3Rpb24oeCkgewogIGRwbHlyOjpjYXNlX3doZW4oCiAgICBpcy5uYSh4KSB+ICIiLAogICAgeCA8IDAuMDAxIH4gIjwgLjAwMSIsCiAgICBUUlVFIH4gc3ViKCJeMCIsICIiLCBmb3JtYXRDKHgsIGZvcm1hdCA9ICJmIiwgZGlnaXRzID0gMykpCiAgKQp9Cgp3cml0ZV9sYXRleF9sb25ndGFibGUgPC0gZnVuY3Rpb24oCiAgICBkYXRhLAogICAgZmlsZSwKICAgIGNhcHRpb24sCiAgICBsYWJlbCwKICAgIG5vdGVzID0gTlVMTCwKICAgIGxhbmRzY2FwZSA9IG5jb2woZGF0YSkgPj0gNykgewogIAogIGRhdGEgPC0gYXMuZGF0YS5mcmFtZShkYXRhLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgaWYgKG5jb2woZGF0YSkgPT0gMCkgewogICAgZGF0YSA8LSBkYXRhLmZyYW1lKG5vdGUgPSAi6Kmy5b2T44GZ44KL5o6o5a6a57WQ5p6c44Gv44GC44KK44G+44Gb44KT44CCIikKICB9CiAgCiAgZGlzcGxheSA8LSBkYXRhCiAgZGlzcGxheVtdIDwtIGxhcHBseShkaXNwbGF5LCBmdW5jdGlvbih4KSBsYXRleF9lc2NhcGUoYXMuY2hhcmFjdGVyKHgpKSkKICBoZWFkZXJzIDwtIGxhdGV4X2VzY2FwZShuYW1lcyhkaXNwbGF5KSkKICAKICBudW1lcmljX2NvbHVtbiA8LSB2YXBwbHkoZGF0YSwgaXMubnVtZXJpYywgbG9naWNhbCgxKSkKICBhbGlnbm1lbnQgPC0gcGFzdGUwKGlmZWxzZShudW1lcmljX2NvbHVtbiwgInIiLCAibCIpLCBjb2xsYXBzZSA9ICIiKQogIAogIGxpbmVzIDwtIGNoYXJhY3RlcigpCiAgbGluZXMgPC0gYyhsaW5lcywgIiUgR2VuZXJhdGVkIGF1dG9tYXRpY2FsbHkgYnkgdGhlIHJlcGxpY2F0aW9uIHNjcmlwdC4iKQogIGlmIChsYW5kc2NhcGUpIHsKICAgIGxpbmVzIDwtIGMobGluZXMsICJcXGJlZ2lue2xhbmRzY2FwZX0iKQogIH0KICBsaW5lcyA8LSBjKAogICAgbGluZXMsCiAgICAiXFxiZWdpbmdyb3VwIiwKICAgICJcXHNtYWxsIiwKICAgIHBhc3RlMCgiXFxiZWdpbntsb25ndGFibGV9eyIsIGFsaWdubWVudCwgIn0iKSwKICAgIHBhc3RlMCgiXFxjYXB0aW9ueyIsIGxhdGV4X2VzY2FwZShjYXB0aW9uKSwgIn1cXGxhYmVseyIsIGxhYmVsLCAifVxcXFwiKSwKICAgICJcXHRvcHJ1bGUiLAogICAgcGFzdGUoaGVhZGVycywgY29sbGFwc2UgPSAiICYgIiksCiAgICAiXFxcXCIsCiAgICAiXFxtaWRydWxlIiwKICAgICJcXGVuZGZpcnN0aGVhZCIsCiAgICBwYXN0ZTAoIlxcbXVsdGljb2x1bW57IiwgbmNvbChkaXNwbGF5KSwgIn17bH17XFx0YWJsZW5hbWV+XFx0aGV0YWJsZXt977yI57aa44GN77yJfVxcXFwiKSwKICAgICJcXHRvcHJ1bGUiLAogICAgcGFzdGUoaGVhZGVycywgY29sbGFwc2UgPSAiICYgIiksCiAgICAiXFxcXCIsCiAgICAiXFxtaWRydWxlIiwKICAgICJcXGVuZGhlYWQiLAogICAgcGFzdGUwKCJcXG1pZHJ1bGVcXG11bHRpY29sdW1ueyIsIG5jb2woZGlzcGxheSksICJ9e3J9e+asoemggeOBq+e2muOBj31cXFxcIiksCiAgICAiXFxlbmRmb290IiwKICAgICJcXGJvdHRvbXJ1bGUiLAogICAgIlxcZW5kbGFzdGZvb3QiCiAgKQogIAogIGlmIChucm93KGRpc3BsYXkpID4gMCkgewogICAgcm93X2xpbmVzIDwtIGFwcGx5KAogICAgICBkaXNwbGF5LAogICAgICAxLAogICAgICBmdW5jdGlvbihyb3cpIHBhc3RlMChwYXN0ZShyb3csIGNvbGxhcHNlID0gIiAmICIpLCAiIFxcXFwiKQogICAgKQogICAgbGluZXMgPC0gYyhsaW5lcywgcm93X2xpbmVzKQogIH0KICAKICBsaW5lcyA8LSBjKGxpbmVzLCAiXFxlbmR7bG9uZ3RhYmxlfSIpCiAgaWYgKCFpcy5udWxsKG5vdGVzKSAmJiBuemNoYXIobm90ZXMpKSB7CiAgICBsaW5lcyA8LSBjKAogICAgICBsaW5lcywKICAgICAgIlxcdnNwYWNley0wLjVlbX0iLAogICAgICAiXFxiZWdpbnttaW5pcGFnZX17XFxsaW5ld2lkdGh9IiwKICAgICAgIlxcZm9vdG5vdGVzaXplIiwKICAgICAgcGFzdGUwKCJcXHRleHRpdHvms6jvvJp9IiwgbGF0ZXhfZXNjYXBlKG5vdGVzKSksCiAgICAgICJcXGVuZHttaW5pcGFnZX0iCiAgICApCiAgfQogIGxpbmVzIDwtIGMobGluZXMsICJcXGVuZGdyb3VwIikKICBpZiAobGFuZHNjYXBlKSB7CiAgICBsaW5lcyA8LSBjKGxpbmVzLCAiXFxlbmR7bGFuZHNjYXBlfSIpCiAgfQogIAogIGRpci5jcmVhdGUoZGlybmFtZShmaWxlKSwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCiAgd3JpdGVMaW5lcyhsaW5lcywgY29uID0gZmlsZSwgdXNlQnl0ZXMgPSBUUlVFKQogIGludmlzaWJsZShmaWxlKQp9Cgp3cml0ZV9jc3ZfYW5kX3RleCA8LSBmdW5jdGlvbigKICAgIGRhdGEsCiAgICBjc3ZfZmlsZSwKICAgIHRleF9maWxlLAogICAgY2FwdGlvbiwKICAgIGxhYmVsLAogICAgbm90ZXMgPSBOVUxMLAogICAgbGFuZHNjYXBlID0gbmNvbChkYXRhKSA+PSA3KSB7CiAgZGlyLmNyZWF0ZShkaXJuYW1lKGNzdl9maWxlKSwgc2hvd1dhcm5pbmdzID0gRkFMU0UsIHJlY3Vyc2l2ZSA9IFRSVUUpCiAgcmVhZHI6OndyaXRlX2NzdihkYXRhLCBjc3ZfZmlsZSwgbmEgPSAiIikKICB3cml0ZV9sYXRleF9sb25ndGFibGUoCiAgICBkYXRhID0gZGF0YSwKICAgIGZpbGUgPSB0ZXhfZmlsZSwKICAgIGNhcHRpb24gPSBjYXB0aW9uLAogICAgbGFiZWwgPSBsYWJlbCwKICAgIG5vdGVzID0gbm90ZXMsCiAgICBsYW5kc2NhcGUgPSBsYW5kc2NhcGUKICApCiAgaW52aXNpYmxlKGxpc3QoY3N2ID0gY3N2X2ZpbGUsIHRleCA9IHRleF9maWxlKSkKfQoKYXR0cmlidXRlX2xhYmVsX21hcCA8LSBjKAogIHBvbGljeV9wb3NpdGlvbiA9ICLmlL/nrZbkvY3nva4iLAogIGdvdmVybm1lbnRfc3RhdHVzID0gIuS4jumHjuWFmuWcsOS9jSIsCiAgc2VhdHMgPSAi6K2w5bit5pWwIiwKICBwYXJ0eV9uYW1lID0gIuaUv+WFmuWQjSIsCiAgZ2RwX2dyb3d0aCA9ICJHRFDmiJDplbfnjociLAogIG5pa2tlaSA9ICLml6XntYzlubPlnYfmoKrkvqEiLAogIGNwaSA9ICLmtojosrvogIXniankvqHmjIfmlbDvvIhDUEnvvIkiLAogIHVuZW1wbG95bWVudCA9ICLlpLHmpa3njociCikKCmN1ZV9mYW1pbHlfbGFiZWwgPC0gYygKICBwYXJ0eSA9ICLmlL/lhZrjga7miYvjgYzjgYvjgooiLAogIGVjb25vbWljID0gIue1jOa4iOOBruaJi+OBjOOBi+OCiiIKKQoKCnNjcmVlbmluZ19zcGVjcyA8LSBsaXN0KAogIHN0dWR5MSA9IGxpc3QoCiAgICBpbml0aWFsX2NvbnNlbnRfdmFyID0gIlExLjEiLAogICAgZmluYWxfY29uc2VudF92YXIgPSBzdHVkeTFfZW52JGZpbmFsX2NvbnNlbnRfdmFyLAogICAgYXR0ZW50aW9uX3ZhciA9IE5BX2NoYXJhY3Rlcl8sCiAgICBhdHRlbnRpb25fYW5zd2VyID0gTkFfY2hhcmFjdGVyXywKICAgIG1hbmlwdWxhdGlvbl9hdmFpbGFibGUgPSBGQUxTRSwKICAgIGludHJvX21hcCA9IE5VTEwKICApLAogIHN0dWR5MiA9IGxpc3QoCiAgICBpbml0aWFsX2NvbnNlbnRfdmFyID0gIlExLjEiLAogICAgZmluYWxfY29uc2VudF92YXIgPSBzdHVkeTJfZW52JGZpbmFsX2NvbnNlbnRfdmFyLAogICAgYXR0ZW50aW9uX3ZhciA9IHN0dWR5Ml9lbnYkYXR0ZW50aW9uX2NoZWNrX3ZhciwKICAgIGF0dGVudGlvbl9hbnN3ZXIgPSBhcy5jaGFyYWN0ZXIoc3R1ZHkyX2VudiRhdHRlbnRpb25fY2hlY2tfY29ycmVjdCksCiAgICBtYW5pcHVsYXRpb25fYXZhaWxhYmxlID0gVFJVRSwKICAgIGludHJvX21hcCA9IE5VTEwKICApLAogIHN0dWR5MyA9IGxpc3QoCiAgICBpbml0aWFsX2NvbnNlbnRfdmFyID0gIlExLjEiLAogICAgZmluYWxfY29uc2VudF92YXIgPSBzdHVkeTNfZW52JGZpbmFsX2NvbnNlbnRfdmFyLAogICAgYXR0ZW50aW9uX3ZhciA9IHN0dWR5M19lbnYkYXR0ZW50aW9uX2NoZWNrX3ZhciwKICAgIGF0dGVudGlvbl9hbnN3ZXIgPSBhcy5jaGFyYWN0ZXIoc3R1ZHkzX2VudiRhdHRlbnRpb25fY2hlY2tfY29ycmVjdCksCiAgICBtYW5pcHVsYXRpb25fYXZhaWxhYmxlID0gVFJVRSwKICAgIGludHJvX21hcCA9IE5VTEwKICApCikKCnJlc3BvbnNlX3ByZXNlbnQgPC0gZnVuY3Rpb24oeCkgewogIHggPC0gYXMuY2hhcmFjdGVyKHgpCiAgIWlzLm5hKHgpICYgc3RyaW5ncjo6c3RyX3NxdWlzaCh4KSAhPSAiIgp9CgpyZXNwb25zZV9pc19jb2RlIDwtIGZ1bmN0aW9uKHgsIGNvZGUpIHsKICB4IDwtIHN0cmluZ3I6OnN0cl9zcXVpc2goYXMuY2hhcmFjdGVyKHgpKQogIGNvZGUgPC0gYXMuY2hhcmFjdGVyKGNvZGUpCiAgb3V0IDwtIHggPT0gY29kZSB8IHN0cmluZ3I6OnN0cl9kZXRlY3QoeCwgcGFzdGUwKCJcXCgiLCBjb2RlLCAiXFwpJCIpKQogIG91dFtpcy5uYShvdXQpXSA8LSBGQUxTRQogIG91dAp9CgpnZXRfbWFwcGVkX3Jlc3BvbnNlIDwtIGZ1bmN0aW9uKGRhdGEsIGFzc2lnbmVkX24sIG1hcCwgdmFsdWVfY29sdW1uKSB7CiAgcmVzdWx0IDwtIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KGRhdGEpKQogIGZvciAobl92YWx1ZSBpbiAyOjUpIHsKICAgIHJvdyA8LSBtYXBbbWFwJHBhcnR5X24gPT0gbl92YWx1ZSwgLCBkcm9wID0gRkFMU0VdCiAgICBpZiAobnJvdyhyb3cpID09IDApIG5leHQKICAgIHZhcmlhYmxlIDwtIGFzLmNoYXJhY3Rlcihyb3dbW3ZhbHVlX2NvbHVtbl1dWzFdKQogICAgaWYgKCF2YXJpYWJsZSAlaW4lIG5hbWVzKGRhdGEpKSBuZXh0CiAgICB0YWtlIDwtICFpcy5uYShhc3NpZ25lZF9uKSAmIGFzc2lnbmVkX24gPT0gbl92YWx1ZQogICAgcmVzdWx0W3Rha2VdIDwtIGFzLmNoYXJhY3RlcihkYXRhW1t2YXJpYWJsZV1dW3Rha2VdKQogIH0KICByZXN1bHQKfQoKaW5mZXJfYXNzaWduZWRfY29uZGl0aW9uIDwtIGZ1bmN0aW9uKGRhdGEsIGNob2ljZV9tYXAsIG1hbmlwdWxhdGlvbl9tYXAgPSBOVUxMLCBpbnRyb19tYXAgPSBOVUxMKSB7CiAgY2FuZGlkYXRlIDwtIG1hdHJpeChGQUxTRSwgbnJvdyA9IG5yb3coZGF0YSksIG5jb2wgPSA0KQogIGNvbG5hbWVzKGNhbmRpZGF0ZSkgPC0gYXMuY2hhcmFjdGVyKDI6NSkKICAKICBmb3IgKG5fdmFsdWUgaW4gMjo1KSB7CiAgICB2YXJpYWJsZXMgPC0gY2hvaWNlX21hcCRjaG9pY2VfdmFyW2Nob2ljZV9tYXAkcGFydHlfbiA9PSBuX3ZhbHVlXQogICAgaWYgKCFpcy5udWxsKG1hbmlwdWxhdGlvbl9tYXApICYmIG5yb3cobWFuaXB1bGF0aW9uX21hcCkgPiAwKSB7CiAgICAgIHZhcmlhYmxlcyA8LSBjKAogICAgICAgIHZhcmlhYmxlcywKICAgICAgICBtYW5pcHVsYXRpb25fbWFwJG1hbmlwdWxhdGlvbl92YXJbbWFuaXB1bGF0aW9uX21hcCRwYXJ0eV9uID09IG5fdmFsdWVdCiAgICAgICkKICAgIH0KICAgIGlmICghaXMubnVsbChpbnRyb19tYXApICYmIGFzLmNoYXJhY3RlcihuX3ZhbHVlKSAlaW4lIG5hbWVzKGludHJvX21hcCkpIHsKICAgICAgdmFyaWFibGVzIDwtIGModmFyaWFibGVzLCB1bm5hbWUoaW50cm9fbWFwW2FzLmNoYXJhY3RlcihuX3ZhbHVlKV0pKQogICAgfQogICAgdmFyaWFibGVzIDwtIGludGVyc2VjdCh1bmlxdWUodmFyaWFibGVzKSwgbmFtZXMoZGF0YSkpCiAgICBpZiAobGVuZ3RoKHZhcmlhYmxlcykgPiAwKSB7CiAgICAgIGNhbmRpZGF0ZVssIGFzLmNoYXJhY3RlcihuX3ZhbHVlKV0gPC0gYXBwbHkoCiAgICAgICAgZGF0YVssIHZhcmlhYmxlcywgZHJvcCA9IEZBTFNFXSwKICAgICAgICAxLAogICAgICAgIGZ1bmN0aW9uKHJvdykgYW55KHJlc3BvbnNlX3ByZXNlbnQocm93KSkKICAgICAgKQogICAgfQogIH0KICAKICBuX2NhbmRpZGF0ZXMgPC0gcm93U3VtcyhjYW5kaWRhdGUpCiAgYXNzaWduZWQgPC0gcmVwKE5BX2ludGVnZXJfLCBucm93KGRhdGEpKQogIHNpbmdsZSA8LSBuX2NhbmRpZGF0ZXMgPT0gMQogIGFzc2lnbmVkW3NpbmdsZV0gPC0gYXMuaW50ZWdlcihjb2xuYW1lcyhjYW5kaWRhdGUpW21heC5jb2woY2FuZGlkYXRlW3NpbmdsZSwgLCBkcm9wID0gRkFMU0VdKV0pCiAgCiAgaWYgKGFueShuX2NhbmRpZGF0ZXMgPiAxKSkgewogICAgd2FybmluZygiQ2hlY2siKQogIH0KICBhc3NpZ25lZAp9CgpidWlsZF9zY3JlZW5pbmdfb3V0cHV0cyA8LSBmdW5jdGlvbihzdHVkeV9zcGVjKSB7CiAgc3R1ZHlfaWQgPC0gc3R1ZHlfc3BlYyRzdHVkeV9pZAogIGVudiA8LSBzdHVkeV9zcGVjJGVudgogIHNwZWMgPC0gc2NyZWVuaW5nX3NwZWNzW1tzdHVkeV9pZF1dCiAgcmF3IDwtIGVudiRkZl9oZWFkZXJfcmVtb3ZlZCAlPiUKICAgIGRwbHlyOjptdXRhdGUoSUQgPSBhcy5jaGFyYWN0ZXIoSUQpKSAlPiUKICAgIGRwbHlyOjpkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKICAKICBtYW5pcHVsYXRpb25fbWFwIDwtIGlmICgKICAgIHNwZWMkbWFuaXB1bGF0aW9uX2F2YWlsYWJsZSAmJgogICAgZXhpc3RzKCJtYW5pcHVsYXRpb25fbWFwIiwgZW52aXIgPSBlbnYsIGluaGVyaXRzID0gRkFMU0UpCiAgKSB7CiAgICBnZXQoIm1hbmlwdWxhdGlvbl9tYXAiLCBlbnZpciA9IGVudiwgaW5oZXJpdHMgPSBGQUxTRSkKICB9IGVsc2UgewogICAgTlVMTAogIH0KICAKICBhc3NpZ25lZF9uIDwtIGluZmVyX2Fzc2lnbmVkX2NvbmRpdGlvbigKICAgIGRhdGEgPSByYXcsCiAgICBjaG9pY2VfbWFwID0gZW52JGNob2ljZV9tYXAsCiAgICBtYW5pcHVsYXRpb25fbWFwID0gbWFuaXB1bGF0aW9uX21hcCwKICAgIGludHJvX21hcCA9IHNwZWMkaW50cm9fbWFwCiAgKQogIAogIGlmIChleGlzdHMoImlkX3Rhc2tfY2hlY2siLCBlbnZpciA9IGVudiwgaW5oZXJpdHMgPSBGQUxTRSkpIHsKICAgIGFuYWx5c2lzX2Fzc2lnbm1lbnQgPC0gZ2V0KCJpZF90YXNrX2NoZWNrIiwgZW52aXIgPSBlbnYsIGluaGVyaXRzID0gRkFMU0UpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgIElEID0gYXMuY2hhcmFjdGVyKElEKSwKICAgICAgICBwYXJ0eV9uID0gYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIocGFydHlfbikpCiAgICAgICkgJT4lCiAgICAgIGRwbHlyOjpncm91cF9ieShJRCkgJT4lCiAgICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgICAgbl9jb25kaXRpb25fY2FuZGlkYXRlcyA9IGRwbHlyOjpuX2Rpc3RpbmN0KHBhcnR5X24pLAogICAgICAgIGFzc2lnbmVkX2Zyb21fYW5hbHlzaXMgPSBkcGx5cjo6aWZfZWxzZSgKICAgICAgICAgIG5fY29uZGl0aW9uX2NhbmRpZGF0ZXMgPT0gMUwsCiAgICAgICAgICBkcGx5cjo6Zmlyc3QocGFydHlfbiksCiAgICAgICAgICBOQV9pbnRlZ2VyXwogICAgICAgICksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApCiAgICAKICAgIGFuYWx5c2lzX21hdGNoIDwtIG1hdGNoKHJhdyRJRCwgYW5hbHlzaXNfYXNzaWdubWVudCRJRCkKICAgIHVzZV9hbmFseXNpc19hc3NpZ25tZW50IDwtICFpcy5uYShhbmFseXNpc19tYXRjaCkgJgogICAgICAhaXMubmEoYW5hbHlzaXNfYXNzaWdubWVudCRhc3NpZ25lZF9mcm9tX2FuYWx5c2lzW2FuYWx5c2lzX21hdGNoXSkKICAgIGFzc2lnbmVkX25bdXNlX2FuYWx5c2lzX2Fzc2lnbm1lbnRdIDwtCiAgICAgIGFuYWx5c2lzX2Fzc2lnbm1lbnQkYXNzaWduZWRfZnJvbV9hbmFseXNpc1thbmFseXNpc19tYXRjaFt1c2VfYW5hbHlzaXNfYXNzaWdubWVudF1dCiAgfQogIAogIGlmIChleGlzdHMoInZhbGlkX2lkcyIsIGVudmlyID0gZW52LCBpbmhlcml0cyA9IEZBTFNFKSkgewogICAgZmluYWxfYXNzaWdubWVudCA8LSBnZXQoInZhbGlkX2lkcyIsIGVudmlyID0gZW52LCBpbmhlcml0cyA9IEZBTFNFKSAlPiUKICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICBJRCA9IGFzLmNoYXJhY3RlcihJRCksCiAgICAgICAgcGFydHlfbiA9IGFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHBhcnR5X24pKQogICAgICApICU+JQogICAgICBkcGx5cjo6ZGlzdGluY3QoSUQsIHBhcnR5X24pICU+JQogICAgICBkcGx5cjo6Z3JvdXBfYnkoSUQpICU+JQogICAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICAgIG5fY29uZGl0aW9uX2NhbmRpZGF0ZXMgPSBkcGx5cjo6bl9kaXN0aW5jdChwYXJ0eV9uKSwKICAgICAgICBhc3NpZ25lZF9mcm9tX2ZpbmFsID0gZHBseXI6OmlmX2Vsc2UoCiAgICAgICAgICBuX2NvbmRpdGlvbl9jYW5kaWRhdGVzID09IDFMLAogICAgICAgICAgZHBseXI6OmZpcnN0KHBhcnR5X24pLAogICAgICAgICAgTkFfaW50ZWdlcl8KICAgICAgICApLAogICAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICAgKQogICAgCiAgICBmaW5hbF9tYXRjaCA8LSBtYXRjaChyYXckSUQsIGZpbmFsX2Fzc2lnbm1lbnQkSUQpCiAgICB1c2VfZmluYWxfYXNzaWdubWVudCA8LSAhaXMubmEoZmluYWxfbWF0Y2gpICYKICAgICAgIWlzLm5hKGZpbmFsX2Fzc2lnbm1lbnQkYXNzaWduZWRfZnJvbV9maW5hbFtmaW5hbF9tYXRjaF0pCiAgICBhc3NpZ25lZF9uW3VzZV9maW5hbF9hc3NpZ25tZW50XSA8LQogICAgICBmaW5hbF9hc3NpZ25tZW50JGFzc2lnbmVkX2Zyb21fZmluYWxbZmluYWxfbWF0Y2hbdXNlX2ZpbmFsX2Fzc2lnbm1lbnRdXQogIH0KICAKICBpbml0aWFsX3Jlc3BvbnNlIDwtIGlmIChzcGVjJGluaXRpYWxfY29uc2VudF92YXIgJWluJSBuYW1lcyhyYXcpKSB7CiAgICByYXdbW3NwZWMkaW5pdGlhbF9jb25zZW50X3Zhcl1dCiAgfSBlbHNlIHsKICAgIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KHJhdykpCiAgfQogIGZpbmFsX3Jlc3BvbnNlIDwtIGlmIChzcGVjJGZpbmFsX2NvbnNlbnRfdmFyICVpbiUgbmFtZXMocmF3KSkgewogICAgcmF3W1tzcGVjJGZpbmFsX2NvbnNlbnRfdmFyXV0KICB9IGVsc2UgewogICAgcmVwKE5BX2NoYXJhY3Rlcl8sIG5yb3cocmF3KSkKICB9CiAgCiAgdGFza19yZXNwb25zZXMgPC0gbGFwcGx5KAogICAgMTo1LAogICAgZnVuY3Rpb24odGFza192YWx1ZSkgewogICAgICB0YXNrX21hcCA8LSBlbnYkY2hvaWNlX21hcFtlbnYkY2hvaWNlX21hcCR0YXNrID09IHRhc2tfdmFsdWUsICwgZHJvcCA9IEZBTFNFXQogICAgICBnZXRfbWFwcGVkX3Jlc3BvbnNlKHJhdywgYXNzaWduZWRfbiwgdGFza19tYXAsICJjaG9pY2VfdmFyIikKICAgIH0KICApCiAgCiAgdGFza19wYXNzIDwtIGxhcHBseSgKICAgIHRhc2tfcmVzcG9uc2VzLAogICAgZnVuY3Rpb24ocmVzcG9uc2UpIHsKICAgICAgcGFyc2VkIDwtIHN1cHByZXNzV2FybmluZ3MocmVhZHI6OnBhcnNlX251bWJlcihhcy5jaGFyYWN0ZXIocmVzcG9uc2UpKSkKICAgICAgIWlzLm5hKGFzc2lnbmVkX24pICYgIWlzLm5hKHBhcnNlZCkgJiBwYXJzZWQgPj0gMSAmIHBhcnNlZCA8PSBhc3NpZ25lZF9uCiAgICB9CiAgKQogIAogIGlmICghaXMubnVsbChtYW5pcHVsYXRpb25fbWFwKSkgewogICAgbWFuaXB1bGF0aW9uX3Jlc3BvbnNlIDwtIGdldF9tYXBwZWRfcmVzcG9uc2UoCiAgICAgIHJhdywKICAgICAgYXNzaWduZWRfbiwKICAgICAgbWFuaXB1bGF0aW9uX21hcCwKICAgICAgIm1hbmlwdWxhdGlvbl92YXIiCiAgICApCiAgICBtYW5pcHVsYXRpb25fYW5zd2VyIDwtIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KHJhdykpCiAgICBmb3IgKG5fdmFsdWUgaW4gMjo1KSB7CiAgICAgIGFuc3dlciA8LSBtYW5pcHVsYXRpb25fbWFwJGNvcnJlY3RfYW5zd2VyW21hbmlwdWxhdGlvbl9tYXAkcGFydHlfbiA9PSBuX3ZhbHVlXQogICAgICBtYW5pcHVsYXRpb25fYW5zd2VyWyFpcy5uYShhc3NpZ25lZF9uKSAmIGFzc2lnbmVkX24gPT0gbl92YWx1ZV0gPC0gYW5zd2VyWzFdCiAgICB9CiAgICBtYW5pcHVsYXRpb25fcGFzcyA8LSAhaXMubmEoYXNzaWduZWRfbikgJiByZXNwb25zZV9pc19jb2RlKAogICAgICBtYW5pcHVsYXRpb25fcmVzcG9uc2UsCiAgICAgIG1hbmlwdWxhdGlvbl9hbnN3ZXIKICAgICkKICB9IGVsc2UgewogICAgbWFuaXB1bGF0aW9uX3Jlc3BvbnNlIDwtIHJlcChOQV9jaGFyYWN0ZXJfLCBucm93KHJhdykpCiAgICBtYW5pcHVsYXRpb25fcGFzcyA8LSByZXAoVFJVRSwgbnJvdyhyYXcpKQogIH0KICAKICBpZiAoIWlzLm5hKHNwZWMkYXR0ZW50aW9uX3ZhcikgJiYgc3BlYyRhdHRlbnRpb25fdmFyICVpbiUgbmFtZXMocmF3KSkgewogICAgYXR0ZW50aW9uX3Jlc3BvbnNlIDwtIHJhd1tbc3BlYyRhdHRlbnRpb25fdmFyXV0KICAgIGF0dGVudGlvbl9wYXNzIDwtIHJlc3BvbnNlX2lzX2NvZGUoYXR0ZW50aW9uX3Jlc3BvbnNlLCBzcGVjJGF0dGVudGlvbl9hbnN3ZXIpCiAgfSBlbHNlIHsKICAgIGF0dGVudGlvbl9yZXNwb25zZSA8LSByZXAoTkFfY2hhcmFjdGVyXywgbnJvdyhyYXcpKQogICAgYXR0ZW50aW9uX3Bhc3MgPC0gcmVwKFRSVUUsIG5yb3cocmF3KSkKICB9CiAgCiAgaW5pdGlhbF9wYXNzIDwtIHJlc3BvbnNlX2lzX2NvZGUoaW5pdGlhbF9yZXNwb25zZSwgMSkgfAogICAgc3RyaW5ncjo6c3RyX2RldGVjdCgKICAgICAgc3RyaW5ncjo6c3RyX3NxdWlzaChhcy5jaGFyYWN0ZXIoaW5pdGlhbF9yZXNwb25zZSkpLAogICAgICAi6Laj5peo44Gr5ZCM5oSP44GX44GmLirljZTlipvjgZnjgosiCiAgICApCiAgZmluYWxfcGFzcyA8LSByZXNwb25zZV9pc19jb2RlKGZpbmFsX3Jlc3BvbnNlLCAxKSB8CiAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KAogICAgICBzdHJpbmdyOjpzdHJfc3F1aXNoKGFzLmNoYXJhY3RlcihmaW5hbF9yZXNwb25zZSkpLAogICAgICAi5ZCM5oSP44GXLirlm57nrZTntZDmnpzjgpLpgIHkv6HjgZnjgosiCiAgICApCiAgCiAgZmluYWxfaWRzIDwtIGFzLmNoYXJhY3RlcihlbnYkdmFsaWRfaWRzJElEKQogIAogIGF1ZGl0IDwtIHRpYmJsZTo6dGliYmxlKAogICAgSUQgPSByYXckSUQsCiAgICBhc3NpZ25lZF9jb25kaXRpb24gPSBhc3NpZ25lZF9uLAogICAgaW5pdGlhbF9jb25zZW50X3Jlc3BvbnNlID0gYXMuY2hhcmFjdGVyKGluaXRpYWxfcmVzcG9uc2UpLAogICAgaW5pdGlhbF9jb25zZW50X3Bhc3MgPSBpbml0aWFsX3Bhc3MsCiAgICByZWFjaGVkX2NvbmpvaW50X2Jsb2NrID0gIWlzLm5hKGFzc2lnbmVkX24pLAogICAgdGFzazFfcmVzcG9uc2UgPSBhcy5jaGFyYWN0ZXIodGFza19yZXNwb25zZXNbWzFdXSksCiAgICB0YXNrMV9jb21wbGV0ZSA9IHRhc2tfcGFzc1tbMV1dLAogICAgdGFzazJfcmVzcG9uc2UgPSBhcy5jaGFyYWN0ZXIodGFza19yZXNwb25zZXNbWzJdXSksCiAgICB0YXNrMl9jb21wbGV0ZSA9IHRhc2tfcGFzc1tbMl1dLAogICAgdGFzazNfcmVzcG9uc2UgPSBhcy5jaGFyYWN0ZXIodGFza19yZXNwb25zZXNbWzNdXSksCiAgICB0YXNrM19jb21wbGV0ZSA9IHRhc2tfcGFzc1tbM11dLAogICAgdGFzazRfcmVzcG9uc2UgPSBhcy5jaGFyYWN0ZXIodGFza19yZXNwb25zZXNbWzRdXSksCiAgICB0YXNrNF9jb21wbGV0ZSA9IHRhc2tfcGFzc1tbNF1dLAogICAgdGFzazVfcmVzcG9uc2UgPSBhcy5jaGFyYWN0ZXIodGFza19yZXNwb25zZXNbWzVdXSksCiAgICB0YXNrNV9jb21wbGV0ZSA9IHRhc2tfcGFzc1tbNV1dLAogICAgYWxsX2ZpdmVfdGFza3NfY29tcGxldGUgPSBSZWR1Y2UoYCZgLCB0YXNrX3Bhc3MpLAogICAgbWFuaXB1bGF0aW9uX3Jlc3BvbnNlID0gYXMuY2hhcmFjdGVyKG1hbmlwdWxhdGlvbl9yZXNwb25zZSksCiAgICBtYW5pcHVsYXRpb25fY2hlY2tfcGFzcyA9IG1hbmlwdWxhdGlvbl9wYXNzLAogICAgYXR0ZW50aW9uX3Jlc3BvbnNlID0gYXMuY2hhcmFjdGVyKGF0dGVudGlvbl9yZXNwb25zZSksCiAgICBhdHRlbnRpb25fY2hlY2tfcGFzcyA9IGF0dGVudGlvbl9wYXNzLAogICAgZmluYWxfY29uc2VudF9yZXNwb25zZSA9IGFzLmNoYXJhY3RlcihmaW5hbF9yZXNwb25zZSksCiAgICBmaW5hbF9jb25zZW50X3Bhc3MgPSBmaW5hbF9wYXNzLAogICAgaW5jbHVkZWRfaW5fZmluYWxfYW5hbHlzaXMgPSBJRCAlaW4lIGZpbmFsX2lkcwogICkKICAKICBjdW11bGF0aXZlIDwtIHJlcChUUlVFLCBucm93KGF1ZGl0KSkKICBzdGFnZV9yZWNvcmRzIDwtIGxpc3QoKQogIGFkZF9zdGFnZSA8LSBmdW5jdGlvbihzdGFnZSwgcXVlc3Rpb25fdmFyaWFibGUsIGNyaXRlcmlvbikgewogICAgY3VtdWxhdGl2ZSA8PC0gY3VtdWxhdGl2ZSAmIGNyaXRlcmlvbgogICAgc3RhZ2VfcmVjb3Jkc1tbbGVuZ3RoKHN0YWdlX3JlY29yZHMpICsgMUxdXSA8PC0gdGliYmxlOjp0aWJibGUoCiAgICAgIHN0YWdlX29yZGVyID0gbGVuZ3RoKHN0YWdlX3JlY29yZHMpICsgMUwsCiAgICAgIHN0YWdlID0gc3RhZ2UsCiAgICAgIHF1ZXN0aW9uX3ZhcmlhYmxlID0gcXVlc3Rpb25fdmFyaWFibGUsCiAgICAgIG5fcmVtYWluaW5nID0gc3VtKGN1bXVsYXRpdmUsIG5hLnJtID0gVFJVRSkKICAgICkKICB9CiAgCiAgYWRkX3N0YWdlKCJRdWFsdHJpY3Pjga7os6rllY/mlofjg7tJbXBvcnRJZOihjOOCkumZpOWkliIsICJSZXNwb25zZUlkIiwgcmVwKFRSVUUsIG5yb3coYXVkaXQpKSkKICBhZGRfc3RhZ2UoIuWIneWbnuWQjOaEjyIsIHNwZWMkaW5pdGlhbF9jb25zZW50X3ZhciwgYXVkaXQkaW5pdGlhbF9jb25zZW50X3Bhc3MpCiAgYWRkX3N0YWdlKCLlibLku5jjgZXjgozjgZ/jgrPjg7Pjgrjjg6fjgqTjg7Pjg4jjg7vjg5bjg63jg4Pjgq/jgavliLDpgZQiLCAiUTMuMS9RNC4xL1E1LjEvUTYuMSDjgb7jgZ/jga/mnIDliJ3jga7pgbjmip7oqrLpoYwiLCBhdWRpdCRyZWFjaGVkX2NvbmpvaW50X2Jsb2NrKQogIGZvciAodGFza192YWx1ZSBpbiAxOjUpIHsKICAgIGFkZF9zdGFnZSgKICAgICAgcGFzdGUwKCLpgbjmip7oqrLpoYwiLCB0YXNrX3ZhbHVlLCAi44KS5pyJ5Yq55Zue562UIiksCiAgICAgIHBhc3RlMCgi5p2h5Lu25YilIGNob2ljZSB0YXNrICIsIHRhc2tfdmFsdWUpLAogICAgICBhdWRpdFtbcGFzdGUwKCJ0YXNrIiwgdGFza192YWx1ZSwgIl9jb21wbGV0ZSIpXV0KICAgICkKICB9CiAgaWYgKHNwZWMkbWFuaXB1bGF0aW9uX2F2YWlsYWJsZSkgewogICAgYWRkX3N0YWdlKAogICAgICAi5o+Q56S644GV44KM44Gf6YG45oqe6IKi5pWw44KS5q2j562UIiwKICAgICAgIuadoeS7tuWIpeOBq+iHquWLleaknOWHuuOBl+OBn+mBuOaKnuiCouaVsOeiuuiqjeizquWVjyIsCiAgICAgIGF1ZGl0JG1hbmlwdWxhdGlvbl9jaGVja19wYXNzCiAgICApCiAgfQogIGlmICghaXMubmEoc3BlYyRhdHRlbnRpb25fdmFyKSkgewogICAgYWRkX3N0YWdlKAogICAgICAi44Kk44OH44Kq44Ot44Ku44O86KGM5YiX44Gu5oyH56S66aCF55uu44Gr5q2j562UIiwKICAgICAgc3BlYyRhdHRlbnRpb25fdmFyLAogICAgICBhdWRpdCRhdHRlbnRpb25fY2hlY2tfcGFzcwogICAgKQogIH0KICBhZGRfc3RhZ2UoIuacgOe1gumAgeS/oeWQjOaEjyIsIHNwZWMkZmluYWxfY29uc2VudF92YXIsIGF1ZGl0JGZpbmFsX2NvbnNlbnRfcGFzcykKICBhZGRfc3RhZ2UoIuacgOe1guWIhuaekOaomeacrCIsICLlhajln7rmupbjga7nqY3pm4blkIgiLCBhdWRpdCRpbmNsdWRlZF9pbl9maW5hbF9hbmFseXNpcykKICAKICBmbG93IDwtIGRwbHlyOjpiaW5kX3Jvd3Moc3RhZ2VfcmVjb3JkcykgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBuX2V4Y2x1ZGVkX2F0X3N0YWdlID0gZHBseXI6OmxhZyhuX3JlbWFpbmluZywgZGVmYXVsdCA9IGRwbHlyOjpmaXJzdChuX3JlbWFpbmluZykpIC0gbl9yZW1haW5pbmcsCiAgICAgIHJldGVudGlvbl9mcm9tX3ByZXZpb3VzX3BjdCA9IGRwbHlyOjppZl9lbHNlKAogICAgICAgIGRwbHlyOjpsYWcobl9yZW1haW5pbmcsIGRlZmF1bHQgPSBkcGx5cjo6Zmlyc3Qobl9yZW1haW5pbmcpKSA+IDAsCiAgICAgICAgMTAwICogbl9yZW1haW5pbmcgLyBkcGx5cjo6bGFnKG5fcmVtYWluaW5nLCBkZWZhdWx0ID0gZHBseXI6OmZpcnN0KG5fcmVtYWluaW5nKSksCiAgICAgICAgTkFfcmVhbF8KICAgICAgKSwKICAgICAgcmV0ZW50aW9uX2Zyb21faW5pdGlhbF9wY3QgPSAxMDAgKiBuX3JlbWFpbmluZyAvIGRwbHlyOjpmaXJzdChuX3JlbWFpbmluZykKICAgICkKICAKICBjb25kaXRpb25fZmxvdyA8LSBwdXJycjo6bWFwX2RmcigKICAgIDI6NSwKICAgIGZ1bmN0aW9uKG5fdmFsdWUpIHsKICAgICAgc3Vic2V0X2F1ZGl0IDwtIGF1ZGl0ICU+JSBkcGx5cjo6ZmlsdGVyKGFzc2lnbmVkX2NvbmRpdGlvbiA9PSBuX3ZhbHVlKQogICAgICBpZiAobnJvdyhzdWJzZXRfYXVkaXQpID09IDApIHsKICAgICAgICByZXR1cm4odGliYmxlOjp0aWJibGUoKSkKICAgICAgfQogICAgICBjcml0ZXJpYSA8LSBsaXN0KAogICAgICAgICLlibLku5jmnaHku7bjgpLorZjliKUiID0gcmVwKFRSVUUsIG5yb3coc3Vic2V0X2F1ZGl0KSksCiAgICAgICAgIumBuOaKnuiqsumhjDEiID0gc3Vic2V0X2F1ZGl0JHRhc2sxX2NvbXBsZXRlLAogICAgICAgICLpgbjmip7oqrLpoYwyIiA9IHN1YnNldF9hdWRpdCR0YXNrMl9jb21wbGV0ZSwKICAgICAgICAi6YG45oqe6Kqy6aGMMyIgPSBzdWJzZXRfYXVkaXQkdGFzazNfY29tcGxldGUsCiAgICAgICAgIumBuOaKnuiqsumhjDQiID0gc3Vic2V0X2F1ZGl0JHRhc2s0X2NvbXBsZXRlLAogICAgICAgICLpgbjmip7oqrLpoYw1IiA9IHN1YnNldF9hdWRpdCR0YXNrNV9jb21wbGV0ZQogICAgICApCiAgICAgIGlmIChzcGVjJG1hbmlwdWxhdGlvbl9hdmFpbGFibGUpIHsKICAgICAgICBjcml0ZXJpYVtbIumBuOaKnuiCouaVsOeiuuiqjSJdXSA8LSBzdWJzZXRfYXVkaXQkbWFuaXB1bGF0aW9uX2NoZWNrX3Bhc3MKICAgICAgfQogICAgICBpZiAoIWlzLm5hKHNwZWMkYXR0ZW50aW9uX3ZhcikpIHsKICAgICAgICBjcml0ZXJpYVtbIuaMh+ekuumgheebriJdXSA8LSBzdWJzZXRfYXVkaXQkYXR0ZW50aW9uX2NoZWNrX3Bhc3MKICAgICAgfQogICAgICBjcml0ZXJpYVtbIuacgOe1gumAgeS/oeWQjOaEjyJdXSA8LSBzdWJzZXRfYXVkaXQkZmluYWxfY29uc2VudF9wYXNzCiAgICAgIGNyaXRlcmlhW1si5pyA57WC5YiG5p6Q5qiZ5pysIl1dIDwtIHN1YnNldF9hdWRpdCRpbmNsdWRlZF9pbl9maW5hbF9hbmFseXNpcwogICAgICAKICAgICAga2VlcCA8LSByZXAoVFJVRSwgbnJvdyhzdWJzZXRfYXVkaXQpKQogICAgICByZWNvcmRzIDwtIHB1cnJyOjppbWFwX2RmcigKICAgICAgICBjcml0ZXJpYSwKICAgICAgICBmdW5jdGlvbihjcml0ZXJpb24sIHN0YWdlX25hbWUpIHsKICAgICAgICAgIGtlZXAgPDwtIGtlZXAgJiBjcml0ZXJpb24KICAgICAgICAgIHRpYmJsZTo6dGliYmxlKAogICAgICAgICAgICBhc3NpZ25lZF9jb25kaXRpb24gPSBuX3ZhbHVlLAogICAgICAgICAgICBzdGFnZV9vcmRlciA9IHdoaWNoKG5hbWVzKGNyaXRlcmlhKSA9PSBzdGFnZV9uYW1lKSwKICAgICAgICAgICAgc3RhZ2UgPSBzdGFnZV9uYW1lLAogICAgICAgICAgICBuX3JlbWFpbmluZyA9IHN1bShrZWVwLCBuYS5ybSA9IFRSVUUpCiAgICAgICAgICApCiAgICAgICAgfQogICAgICApCiAgICAgIHJlY29yZHMgJT4lCiAgICAgICAgZHBseXI6Om11dGF0ZSgKICAgICAgICAgIG5fZXhjbHVkZWRfYXRfc3RhZ2UgPSBkcGx5cjo6bGFnKG5fcmVtYWluaW5nLCBkZWZhdWx0ID0gZHBseXI6OmZpcnN0KG5fcmVtYWluaW5nKSkgLSBuX3JlbWFpbmluZywKICAgICAgICAgIHJldGVudGlvbl9mcm9tX2NvbmRpdGlvbl9zdGFydF9wY3QgPSAxMDAgKiBuX3JlbWFpbmluZyAvIGRwbHlyOjpmaXJzdChuX3JlbWFpbmluZykKICAgICAgICApCiAgICB9CiAgKQogIAogIGZpbmFsX2F1ZGl0IDwtIGF1ZGl0ICU+JSBkcGx5cjo6ZmlsdGVyKGluY2x1ZGVkX2luX2ZpbmFsX2FuYWx5c2lzKQogIHJlcXVpcmVkX2ZpbmFsIDwtIGZpbmFsX2F1ZGl0JGluaXRpYWxfY29uc2VudF9wYXNzICYKICAgIGZpbmFsX2F1ZGl0JGFsbF9maXZlX3Rhc2tzX2NvbXBsZXRlICYKICAgIGZpbmFsX2F1ZGl0JG1hbmlwdWxhdGlvbl9jaGVja19wYXNzICYKICAgIGZpbmFsX2F1ZGl0JGF0dGVudGlvbl9jaGVja19wYXNzICYKICAgIGZpbmFsX2F1ZGl0JGZpbmFsX2NvbnNlbnRfcGFzcwogIGlmICghYWxsKHJlcXVpcmVkX2ZpbmFsKSkgewogICAgc3RvcCgiQ2hlY2siKQogIH0KICBpZiAobnJvdyhmaW5hbF9hdWRpdCkgIT0gZHBseXI6Om5fZGlzdGluY3QoZW52JHZhbGlkX2lkcyRJRCkpIHsKICAgIHN0b3AoIkNoZWNrIikKICB9CiAgCiAgbGlzdChhdWRpdCA9IGF1ZGl0LCBmbG93ID0gZmxvdywgY29uZGl0aW9uX2Zsb3cgPSBjb25kaXRpb25fZmxvdykKfQoKCm1ha2VfYW1jZV90YWJsZSA8LSBmdW5jdGlvbihlbnYsIGFkanVzdGVkID0gVFJVRSkgewogIHNvdXJjZSA8LSBpZiAoYWRqdXN0ZWQpIGVudiRhbWNlX3Bsb3RfY292IGVsc2UgZW52JGFtY2VfcGxvdF9ub2NvdgogIG5fdGFibGUgPC0gZW52JG5fYnlfcGFydHkgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBwYXJ0eV9uX251bWVyaWMgPSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihwYXJ0eV9uKSksCiAgICAgIHJlc3BvbmRlbnRzID0gbgogICAgKQogIAogIHNvdXJjZSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIHBhcnR5X25fbnVtZXJpYyA9IHN1cHByZXNzV2FybmluZ3MocmVhZHI6OnBhcnNlX251bWJlcihhcy5jaGFyYWN0ZXIocGFydHlfbikpKQogICAgKSAlPiUKICAgIGRwbHlyOjpsZWZ0X2pvaW4obl90YWJsZSwgYnkgPSAicGFydHlfbl9udW1lcmljIikgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBg5p2h5Lu2YCA9IGFzLmNoYXJhY3RlcihwYXJ0eV9uKSwKICAgICAgYOWxnuaAp2AgPSBhcy5jaGFyYWN0ZXIoYXR0cmlidXRlKSwKICAgICAgYOawtOa6lu+8iOWfuua6luawtOa6luOBqOOBruW3ru+8iWAgPSBhcy5jaGFyYWN0ZXIobGFiZWwpLAogICAgICBg5o6o5a6a5YCk77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBlc3RpbWF0ZSwgMiksCiAgICAgIGDmqJnmupboqqTlt67vvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIHN0ZC5lcnJvciwgMiksCiAgICAgIGA5NSUgQ0nkuIvpmZDvvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIGNvbmYubG93LCAyKSwKICAgICAgYDk1JSBDSeS4iumZkO+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogY29uZi5oaWdoLCAyKSwKICAgICAgYHDlgKRgID0gZm9ybWF0X3BfdmFsdWUocC52YWx1ZSksCiAgICAgIGDlm57nrZTogIXmlbBgID0gZm9ybWF0X2ludGVnZXIocmVzcG9uZGVudHMpCiAgICApCn0KCm1ha2VfaW50ZXJhY3Rpb25fdGFibGUgPC0gZnVuY3Rpb24oZW52KSB7CiAgc291cmNlIDwtIGVudiRpbnRlcmFjdGlvbl9wbG90X2RmCiAgY29uZGl0aW9uX2NvbHVtbiA8LSBpbnRlcnNlY3QoYygicGFydHlfbl9sYWJlbCIsICJwYXJ0eV9uIiksIG5hbWVzKHNvdXJjZSkpWzFdCiAgaWYgKGlzLm5hKGNvbmRpdGlvbl9jb2x1bW4pKSB7CiAgICBzb3VyY2UkY29uZGl0aW9uX2xhYmVsIDwtICIiCiAgfSBlbHNlIHsKICAgIHNvdXJjZSRjb25kaXRpb25fbGFiZWwgPC0gYXMuY2hhcmFjdGVyKHNvdXJjZVtbY29uZGl0aW9uX2NvbHVtbl1dKQogIH0KICBzb3VyY2UgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBg5q+U6LyD5p2h5Lu2YCA9IGNvbmRpdGlvbl9sYWJlbCwKICAgICAgYOWxnuaAp2AgPSBhcy5jaGFyYWN0ZXIoYXR0cmlidXRlKSwKICAgICAgYOawtOa6lmAgPSBhcy5jaGFyYWN0ZXIobGFiZWwpLAogICAgICBgMumBuOaKnuiCouadoeS7tuOBqOOBruW3ru+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogZXN0aW1hdGUsIDIpLAogICAgICBg5qiZ5rqW6Kqk5beu77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBzdGQuZXJyb3IsIDIpLAogICAgICBgOTUlIENJ5LiL6ZmQ77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBjb25mLmxvdywgMiksCiAgICAgIGA5NSUgQ0nkuIrpmZDvvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIGNvbmYuaGlnaCwgMiksCiAgICAgIGBw5YCkYCA9IGZvcm1hdF9wX3ZhbHVlKHAudmFsdWUpCiAgICApCn0KCmNsdXN0ZXJlZF9tZWFuX3N1bW1hcnkgPC0gZnVuY3Rpb24oeSwgY2x1c3RlcikgewogIHkgPC0gYXMubnVtZXJpYyh5KQogIGNsdXN0ZXIgPC0gYXMuY2hhcmFjdGVyKGNsdXN0ZXIpCiAga2VlcCA8LSBpcy5maW5pdGUoeSkgJiAhaXMubmEoY2x1c3RlcikKICB5IDwtIHlba2VlcF0KICBjbHVzdGVyIDwtIGNsdXN0ZXJba2VlcF0KICBuIDwtIGxlbmd0aCh5KQogIGcgPC0gZHBseXI6Om5fZGlzdGluY3QoY2x1c3RlcikKICBpZiAobiA9PSAwKSB7CiAgICByZXR1cm4oYyhlc3RpbWF0ZSA9IE5BX3JlYWxfLCBzZSA9IE5BX3JlYWxfLCBsb3cgPSBOQV9yZWFsXywgaGlnaCA9IE5BX3JlYWxfLCBuID0gMCwgZyA9IDApKQogIH0KICBlc3RpbWF0ZSA8LSBtZWFuKHkpCiAgaWYgKGcgPD0gMSkgewogICAgc2UgPC0gTkFfcmVhbF8KICB9IGVsc2UgewogICAgY2x1c3Rlcl9zY29yZSA8LSB0YXBwbHkoeSAtIGVzdGltYXRlLCBjbHVzdGVyLCBzdW0pCiAgICB2YXJpYW5jZSA8LSAoZyAvIChnIC0gMSkpICogc3VtKGNsdXN0ZXJfc2NvcmVeMikgLyAobl4yKQogICAgc2UgPC0gc3FydCh2YXJpYW5jZSkKICB9CiAgYygKICAgIGVzdGltYXRlID0gZXN0aW1hdGUsCiAgICBzZSA9IHNlLAogICAgbG93ID0gZXN0aW1hdGUgLSAxLjk2ICogc2UsCiAgICBoaWdoID0gZXN0aW1hdGUgKyAxLjk2ICogc2UsCiAgICBuID0gbiwKICAgIGcgPSBnCiAgKQp9CgptYWtlX21tX3RhYmxlIDwtIGZ1bmN0aW9uKGVudikgewogIGF0dHJpYnV0ZXMgPC0gbmFtZXMoZW52JHJlbGF0aXZlX2N1ZV9tYXApCiAgbG9uZyA8LSBlbnYkY29uam9pbnRfYWxsX20gJT4lCiAgICBkcGx5cjo6c2VsZWN0KElELCBwYXJ0eV9uLCBzZWxlY3RlZCwgZHBseXI6OmFsbF9vZihhdHRyaWJ1dGVzKSkgJT4lCiAgICB0aWR5cjo6cGl2b3RfbG9uZ2VyKAogICAgICBjb2xzID0gZHBseXI6OmFsbF9vZihhdHRyaWJ1dGVzKSwKICAgICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwKICAgICAgdmFsdWVzX3RvID0gImxldmVsIgogICAgKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGxldmVsKSwgYXMuY2hhcmFjdGVyKGxldmVsKSAhPSAiIikgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxldmVsID0gYXMuY2hhcmFjdGVyKGxldmVsKSkKICAKICBzdW1tYXJ5IDwtIGxvbmcgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkocGFydHlfbiwgYXR0cmlidXRlLCBsZXZlbCkgJT4lCiAgICBkcGx5cjo6Z3JvdXBfbW9kaWZ5KAogICAgICB+IHsKICAgICAgICB2YWx1ZXMgPC0gY2x1c3RlcmVkX21lYW5fc3VtbWFyeSgueCRzZWxlY3RlZCwgLngkSUQpCiAgICAgICAgdGliYmxlOjp0aWJibGUoCiAgICAgICAgICBtYXJnaW5hbF9tZWFuID0gdmFsdWVzWyJlc3RpbWF0ZSJdLAogICAgICAgICAgY2x1c3Rlcl9zZSA9IHZhbHVlc1sic2UiXSwKICAgICAgICAgIGNvbmZfbG93ID0gdmFsdWVzWyJsb3ciXSwKICAgICAgICAgIGNvbmZfaGlnaCA9IHZhbHVlc1siaGlnaCJdLAogICAgICAgICAgbl9wcm9maWxlcyA9IHZhbHVlc1sibiJdLAogICAgICAgICAgbl9yZXNwb25kZW50cyA9IHZhbHVlc1siZyJdCiAgICAgICAgKQogICAgICB9CiAgICApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIGN1ZV9mYW1pbHkgPSB1bm5hbWUoZW52JHJlbGF0aXZlX2N1ZV9tYXBbYXR0cmlidXRlXSksCiAgICAgIGF0dHJpYnV0ZV9sYWJlbCA9IGRwbHlyOjpjb2FsZXNjZSh1bm5hbWUoYXR0cmlidXRlX2xhYmVsX21hcFthdHRyaWJ1dGVdKSwgYXR0cmlidXRlKSwKICAgICAgY3VlX2xhYmVsID0gZHBseXI6OmNvYWxlc2NlKHVubmFtZShjdWVfZmFtaWx5X2xhYmVsW2N1ZV9mYW1pbHldKSwgY3VlX2ZhbWlseSkKICAgICkKICAKICBzdW1tYXJ5ICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOadoeS7tmAgPSBwYXN0ZTAocGFydHlfbiwgaWZlbHNlKCJwYXJ0eV9uYW1lIiAlaW4lIGF0dHJpYnV0ZXMsICLpgbjmip7ogqIiLCAi5pS/5YWaIikpLAogICAgICBg5omL44GM44GL44KK576kYCA9IGN1ZV9sYWJlbCwKICAgICAgYOWxnuaAp2AgPSBhdHRyaWJ1dGVfbGFiZWwsCiAgICAgIGDmsLTmupZgID0gbGV2ZWwsCiAgICAgIGDpmZDnlYzlubPlnYfvvIgl77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogbWFyZ2luYWxfbWVhbiwgMiksCiAgICAgIGDjgq/jg6njgrnjgr9TRe+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogY2x1c3Rlcl9zZSwgMiksCiAgICAgIGA5NSUgQ0nkuIvpmZDvvIgl77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogY29uZl9sb3csIDIpLAogICAgICBgOTUlIENJ5LiK6ZmQ77yIJe+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIGNvbmZfaGlnaCwgMiksCiAgICAgIGDjg5fjg63jg5XjgqHjgqTjg6vmlbBgID0gZm9ybWF0X2ludGVnZXIobl9wcm9maWxlcyksCiAgICAgIGDlm57nrZTogIXmlbBgID0gZm9ybWF0X2ludGVnZXIobl9yZXNwb25kZW50cykKICAgICkKfQoKbWFrZV9hdHRyaWJ1dGVfaW1wb3J0YW5jZV90YWJsZSA8LSBmdW5jdGlvbihlbnYpIHsKICBzb3VyY2UgPC0gZW52JHJlbGF0aXZlX2N1ZV9vYnNlcnZlZCRhdHRyaWJ1dGVfaW1wb3J0YW5jZQogIGFkanVzdGVkX2NvbCA8LSBpbnRlcnNlY3QoCiAgICBjKCJpbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkIiwgImNob2ljZV9zZXRfYWRqdXN0ZWRfaW1wb3J0YW5jZV9wYWlyd2lzZSIpLAogICAgbmFtZXMoc291cmNlKQogIClbMV0KICBhZGp1c3RlZCA8LSBpZiAoIWlzLm5hKGFkanVzdGVkX2NvbCkpIHNvdXJjZVtbYWRqdXN0ZWRfY29sXV0gZWxzZSBzb3VyY2UkcGFydHlfbiAqIHNvdXJjZSRpbXBvcnRhbmNlX3BhaXJ3aXNlCiAgCiAgc291cmNlICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgYWRqdXN0ZWRfdmFsdWUgPSBhZGp1c3RlZCwKICAgICAgYXR0cmlidXRlX2xhYmVsID0gZHBseXI6OmNvYWxlc2NlKHVubmFtZShhdHRyaWJ1dGVfbGFiZWxfbWFwW2F0dHJpYnV0ZV0pLCBhdHRyaWJ1dGUpLAogICAgICBjdWVfbGFiZWwgPSBkcGx5cjo6Y29hbGVzY2UodW5uYW1lKGN1ZV9mYW1pbHlfbGFiZWxbY3VlX2ZhbWlseV0pLCBjdWVfZmFtaWx5KQogICAgKSAlPiUKICAgIGRwbHlyOjp0cmFuc211dGUoCiAgICAgIGDmnaHku7ZgID0gcGFydHlfbiwKICAgICAgYOaJi+OBjOOBi+OCiue+pGAgPSBjdWVfbGFiZWwsCiAgICAgIGDlsZ7mgKdgID0gYXR0cmlidXRlX2xhYmVsLAogICAgICBg5rC05rqW5pWwYCA9IG5fbGV2ZWxzLAogICAgICBg5pyq6Kq/5pW06YeN6KaB5bqm77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBpbXBvcnRhbmNlX3BhaXJ3aXNlLCAyKSwKICAgICAgYOmBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6pu+8iCXvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBhZGp1c3RlZF92YWx1ZSwgMikKICAgICkKfQoKbWFrZV9jdWVfaW1wb3J0YW5jZV90YWJsZSA8LSBmdW5jdGlvbihlbnYpIHsKICBzb3VyY2UgPC0gZW52JHJlbGF0aXZlX2N1ZV9jb25kaXRpb25faW50ZXJ2YWxzCiAgbGFiZWxzIDwtIGMoCiAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlID0gIuaUv+WFmuaJi+OBjOOBi+OCiu+8muacquiqv+aVtOmHjeimgeW6piIsCiAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlID0gIue1jOa4iOaJi+OBjOOBi+OCiu+8muacquiqv+aVtOmHjeimgeW6piIsCiAgICBwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0gIuaUv+WFmuaJi+OBjOOBi+OCiu+8mumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6piIsCiAgICBlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlX2FkanVzdGVkID0gIue1jOa4iOaJi+OBjOOBi+OCiu+8mumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6piIsCiAgICByZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UgPSAi5pS/5YWa5omL44GM44GL44KK44Gu55u45a++5q+U6YeNIgogICkKICBzb3VyY2UgPC0gc291cmNlICU+JSBkcGx5cjo6ZmlsdGVyKHN0YXRpc3RpYyAlaW4lIG5hbWVzKGxhYmVscykpCiAgc291cmNlICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgYOaMh+aomWAgPSB1bm5hbWUobGFiZWxzW3N0YXRpc3RpY10pLAogICAgICBg5Y2Y5L2NYCA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgICAgc3RhdGlzdGljICVpbiUgYygicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZSIsICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIikgfiAicHAiLAogICAgICAgIFRSVUUgfiAiJSIKICAgICAgKSwKICAgICAgbXVsdGlwbGllciA9IDEwMAogICAgKSAlPiUKICAgIGRwbHlyOjp0cmFuc211dGUoCiAgICAgIGDmnaHku7ZgID0gcGFydHlfbiwKICAgICAgYOaMh+aomWAgPSBg5oyH5qiZYCwKICAgICAgYOWNmOS9jWAgPSBg5Y2Y5L2NYCwKICAgICAgYOaOqOWumuWApGAgPSBmb3JtYXRfbnVtYmVyKG11bHRpcGxpZXIgKiBlc3RpbWF0ZSwgMiksCiAgICAgIGA5NSUgQ0nkuIvpmZBgID0gZm9ybWF0X251bWJlcihtdWx0aXBsaWVyICogY29uZl9sb3csIDIpLAogICAgICBgOTUlIENJ5LiK6ZmQYCA9IGZvcm1hdF9udW1iZXIobXVsdGlwbGllciAqIGNvbmZfaGlnaCwgMikKICAgICkKfQoKbWFrZV9jbG9naXRfdGFibGUgPC0gZnVuY3Rpb24oZW52KSB7CiAgZW52JGNsb2dpdF9wbG90X2RmICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOadoeS7tmAgPSBhcy5jaGFyYWN0ZXIocGFydHlfbiksCiAgICAgIGDlsZ7mgKdgID0gYXMuY2hhcmFjdGVyKGF0dHJpYnV0ZSksCiAgICAgIGDmsLTmupbvvIjln7rmupbmsLTmupbjgajjga7lt67vvIlgID0gYXMuY2hhcmFjdGVyKGxhYmVsKSwKICAgICAgYGxvZ+S/guaVsGAgPSBmb3JtYXRfbnVtYmVyKGVzdGltYXRlLCAzKSwKICAgICAgYOaomea6luiqpOW3rmAgPSBmb3JtYXRfbnVtYmVyKHN0ZC5lcnJvciwgMyksCiAgICAgIGDjgqrjg4Pjgrrmr5RgID0gZm9ybWF0X251bWJlcihvZGRzX3JhdGlvLCAzKSwKICAgICAgYDk1JSBDSeS4i+mZkO+8iE9S77yJYCA9IGZvcm1hdF9udW1iZXIob2Rkc19yYXRpb19sb3csIDMpLAogICAgICBgOTUlIENJ5LiK6ZmQ77yIT1LvvIlgID0gZm9ybWF0X251bWJlcihvZGRzX3JhdGlvX2hpZ2gsIDMpLAogICAgICBgcOWApGAgPSBmb3JtYXRfcF92YWx1ZShwLnZhbHVlKQogICAgKQp9CgptYWtlX2xpbmVhcl90cmVuZF90YWJsZSA8LSBmdW5jdGlvbihlbnYpIHsKICBpZiAoIWV4aXN0cygibGluZWFyX3RyZW5kX3Bsb3RfZGYiLCBlbnZpciA9IGVudiwgaW5oZXJpdHMgPSBGQUxTRSkpIHsKICAgIHJldHVybih0aWJibGU6OnRpYmJsZSgpKQogIH0KICBlbnYkbGluZWFyX3RyZW5kX3Bsb3RfZGYgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBg5bGe5oCnYCA9IGFzLmNoYXJhY3RlcihhdHRyaWJ1dGUpLAogICAgICBg5rC05rqWYCA9IGFzLmNoYXJhY3RlcihsYWJlbCksCiAgICAgIGDpgbjmip7ogqLjgYwx44Gk5aKX44GI44KL44Go44GN44Gu5aSJ5YyW77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBlc3RpbWF0ZSwgMiksCiAgICAgIGDmqJnmupboqqTlt67vvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIHN0ZC5lcnJvciwgMiksCiAgICAgIGA5NSUgQ0nkuIvpmZDvvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIGNvbmYubG93LCAyKSwKICAgICAgYDk1JSBDSeS4iumZkO+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogY29uZi5oaWdoLCAyKSwKICAgICAgYHDlgKRgID0gZm9ybWF0X3BfdmFsdWUocC52YWx1ZSkKICAgICkKfQoKbWFrZV9wYXJ0eV9tYXRjaF90YWJsZSA8LSBmdW5jdGlvbihlbnYpIHsKICBpZiAoIWV4aXN0cygicGFydHlfbWF0Y2hfY29lZl9kZiIsIGVudmlyID0gZW52LCBpbmhlcml0cyA9IEZBTFNFKSkgewogICAgcmV0dXJuKHRpYmJsZTo6dGliYmxlKCkpCiAgfQogIG92ZXJhbGwgPC0gZW52JHBhcnR5X21hdGNoX2NvZWZfZGYKICBzdWJncm91cCA8LSBpZiAoZXhpc3RzKCJwYXJ0eV9tYXRjaF9zdWJncm91cF9jb2VmX2RmIiwgZW52aXIgPSBlbnYsIGluaGVyaXRzID0gRkFMU0UpKSB7CiAgICBlbnYkcGFydHlfbWF0Y2hfc3ViZ3JvdXBfY29lZl9kZgogIH0gZWxzZSB7CiAgICB0aWJibGU6OnRpYmJsZSgpCiAgfQogIGNvbWJpbmVkIDwtIGRwbHlyOjpiaW5kX3Jvd3Mob3ZlcmFsbCwgc3ViZ3JvdXApCiAgaWYgKCEibl9pZHMiICVpbiUgbmFtZXMoY29tYmluZWQpKSBjb21iaW5lZCRuX2lkcyA8LSBOQV9yZWFsXwogIGlmICghInN1cHBvcnRfZ3JvdXBfbGFiZWwiICVpbiUgbmFtZXMoY29tYmluZWQpKSBjb21iaW5lZCRzdXBwb3J0X2dyb3VwX2xhYmVsIDwtICLlhajkvZMiCiAgY29tYmluZWQgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBzdXBwb3J0X2dyb3VwX2xhYmVsID0gZHBseXI6OmNvYWxlc2NlKGFzLmNoYXJhY3RlcihzdXBwb3J0X2dyb3VwX2xhYmVsKSwgIuWFqOS9kyIpLAogICAgICBuX2lkcyA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhuX2lkcykpCiAgICApICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOWvvuixoWAgPSBzdXBwb3J0X2dyb3VwX2xhYmVsLAogICAgICBg6YG45oqe6IKi5pWwYCA9IHBhcnR5X24sCiAgICAgIGDkuIDoh7TlirnmnpzvvIhwcO+8iWAgPSBmb3JtYXRfbnVtYmVyKDEwMCAqIGVzdGltYXRlLCAyKSwKICAgICAgYOaomea6luiqpOW3ru+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogc3RkLmVycm9yLCAyKSwKICAgICAgYDk1JSBDSeS4i+mZkO+8iHBw77yJYCA9IGZvcm1hdF9udW1iZXIoMTAwICogY29uZi5sb3csIDIpLAogICAgICBgOTUlIENJ5LiK6ZmQ77yIcHDvvIlgID0gZm9ybWF0X251bWJlcigxMDAgKiBjb25mLmhpZ2gsIDIpLAogICAgICBgcOWApGAgPSBmb3JtYXRfcF92YWx1ZShwLnZhbHVlKSwKICAgICAgYOWbnuetlOiAheaVsGAgPSBmb3JtYXRfaW50ZWdlcihuX2lkcykKICAgICkKfQoKCnNjcmVlbmluZ19yZXN1bHRzIDwtIGxpc3QoKQpzdHVkeV90YWJsZV9wYXRocyA8LSBsaXN0KCkKCmZvciAoc3R1ZHlfaWQgaW4gbmFtZXMoc3R1ZHlfc3BlY3MpKSB7CiAgc3BlYyA8LSBzdHVkeV9zcGVjc1tbc3R1ZHlfaWRdXQogIGVudiA8LSBzcGVjJGVudgogIHN0dWR5X2xhYmVsIDwtIHNwZWMkc3R1ZHlfbGFiZWwKICBjc3ZfZGlyIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgc3R1ZHlfaWQsICJ0YWJsZXNfY3N2IikKICB0ZXhfZGlyIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgc3R1ZHlfaWQsICJ0YWJsZXNfdGV4IikKICBkaWFnX3NjcmVlbl9kaXIgPC0gZmlsZS5wYXRoKGZpbmFsX2RpcnMkZGlhZ25vc3RpY3Nfcm9vdCwgc3R1ZHlfaWQsICJzY3JlZW5pbmciKQogIGRpYWdfYmFsYW5jZV9kaXIgPC0gZmlsZS5wYXRoKGZpbmFsX2RpcnMkZGlhZ25vc3RpY3Nfcm9vdCwgc3R1ZHlfaWQsICJiYWxhbmNlIikKICBkaWFnX3JhbmRvbV9kaXIgPC0gZmlsZS5wYXRoKGZpbmFsX2RpcnMkZGlhZ25vc3RpY3Nfcm9vdCwgc3R1ZHlfaWQsICJyYW5kb21pemF0aW9uIikKICAKICBzY3JlZW5pbmcgPC0gYnVpbGRfc2NyZWVuaW5nX291dHB1dHMoc3BlYykKICBzY3JlZW5pbmdfcmVzdWx0c1tbc3R1ZHlfaWRdXSA8LSBzY3JlZW5pbmcKICAKICByZWFkcjo6d3JpdGVfY3N2KHNjcmVlbmluZyRhdWRpdCwgZmlsZS5wYXRoKGRpYWdfc2NyZWVuX2RpciwgInJlc3BvbmRlbnRfc2NyZWVuaW5nX2F1ZGl0LmNzdiIpLCBuYSA9ICIiKQogIHJlYWRyOjp3cml0ZV9jc3Yoc2NyZWVuaW5nJGZsb3csIGZpbGUucGF0aChkaWFnX3NjcmVlbl9kaXIsICJzZXF1ZW50aWFsX3NhbXBsZV9mbG93LmNzdiIpLCBuYSA9ICIiKQogIHJlYWRyOjp3cml0ZV9jc3Yoc2NyZWVuaW5nJGNvbmRpdGlvbl9mbG93LCBmaWxlLnBhdGgoZGlhZ19zY3JlZW5fZGlyLCAic2VxdWVudGlhbF9zYW1wbGVfZmxvd19ieV9jb25kaXRpb24uY3N2IiksIG5hID0gIiIpCiAgCiAgYXR0cml0aW9uX3RhYmxlIDwtIHNjcmVlbmluZyRmbG93ICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOmghuW6j2AgPSBzdGFnZV9vcmRlciwKICAgICAgYOautemajmAgPSBzdGFnZSwKICAgICAgYOizquWVj+ODu+WkieaVsGAgPSBxdWVzdGlvbl92YXJpYWJsZSwKICAgICAgYOaui+WtmE5gID0gZm9ybWF0X2ludGVnZXIobl9yZW1haW5pbmcpLAogICAgICBg5b2T6Kmy5q616ZqO44Gn44Gu6Zmk5aSWTmAgPSBmb3JtYXRfaW50ZWdlcihuX2V4Y2x1ZGVkX2F0X3N0YWdlKSwKICAgICAgYOWJjeautemajuOBi+OCieOBruaui+WtmOeOh++8iCXvvIlgID0gZm9ybWF0X251bWJlcihyZXRlbnRpb25fZnJvbV9wcmV2aW91c19wY3QsIDEpLAogICAgICBg5Yid5pyf5qiZ5pys44GL44KJ44Gu5q6L5a2Y546H77yIJe+8iWAgPSBmb3JtYXRfbnVtYmVyKHJldGVudGlvbl9mcm9tX2luaXRpYWxfcGN0LCAxKQogICAgKQogIAogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgYXR0cml0aW9uX3RhYmxlLAogICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9zYW1wbGVfYXR0cml0aW9uLmNzdiIpLAogICAgZmlsZS5wYXRoKHRleF9kaXIsICJ0YWJsZV9zYW1wbGVfYXR0cml0aW9uLnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya6LOq5ZWP5q616ZqO44GU44Go44Gu6YCQ5qyh55qE44Gq5qiZ5pys5rib5bCRIiksCiAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1hdHRyaXRpb24iKSwKICAgIG5vdGVzID0gcGFzdGUwKAogICAgICAi5ZCE6KGM44Gv55u05YmN44G+44Gn44Gu5Z+65rqW44KS5rqA44Gf44GX44Gf5Zue562U6ICF44Gr5qyh44Gu5Z+65rqW44KS6aCG44Gr6YGp55So44GX44Gf5q6L5a2Y5pWw44KS56S644GZ44CCIiwKICAgICAgaWZlbHNlKAogICAgICAgIHN0dWR5X2lkID09ICJzdHVkeTEiLAogICAgICAgICJTdHVkeSAx44Gn44Gv6YG45oqe6IKi5pWw56K66KqN6LOq5ZWP44GK44KI44Gz5oyH56S66aCF55uu44Gv6Kq/5p+756Wo44Gr6Kit44GR44KJ44KM44Gm44GE44Gq44GE44CCIiwKICAgICAgICAi5pyA57WC5YiG5p6Q44Gv44CB6YG45oqe6IKi5pWw56K66KqN44GoUTI1LjFfMTHjga7mjIfnpLrpoIXnm67jga7lj4zmlrnjgavmraPnrZTjgZfjgZ/lm57nrZTogIXjgavpmZDlrprjgZfjgZ/jgIIiCiAgICAgICkKICAgICkKICApCiAgCiAgY29uZGl0aW9uX2F0dHJpdGlvbl90YWJsZSA8LSBzY3JlZW5pbmckY29uZGl0aW9uX2Zsb3cgJT4lCiAgICBkcGx5cjo6dHJhbnNtdXRlKAogICAgICBg5p2h5Lu2YCA9IGFzc2lnbmVkX2NvbmRpdGlvbiwKICAgICAgYOmghuW6j2AgPSBzdGFnZV9vcmRlciwKICAgICAgYOautemajmAgPSBzdGFnZSwKICAgICAgYOaui+WtmE5gID0gZm9ybWF0X2ludGVnZXIobl9yZW1haW5pbmcpLAogICAgICBg5b2T6Kmy5q616ZqO44Gn44Gu6Zmk5aSWTmAgPSBmb3JtYXRfaW50ZWdlcihuX2V4Y2x1ZGVkX2F0X3N0YWdlKSwKICAgICAgYOadoeS7tumWi+Wni+aZguOBi+OCieOBruaui+WtmOeOh++8iCXvvIlgID0gZm9ybWF0X251bWJlcihyZXRlbnRpb25fZnJvbV9jb25kaXRpb25fc3RhcnRfcGN0LCAxKQogICAgKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgY29uZGl0aW9uX2F0dHJpdGlvbl90YWJsZSwKICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfc2FtcGxlX2F0dHJpdGlvbl9ieV9jb25kaXRpb24uY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX3NhbXBsZV9hdHRyaXRpb25fYnlfY29uZGl0aW9uLnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya5p2h5Lu25Yil44Gu6YCQ5qyh55qE44Gq5qiZ5pys5rib5bCRIiksCiAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1hdHRyaXRpb24tY29uZGl0aW9uIiksCiAgICBub3RlcyA9ICLmnaHku7bjgpLlm57nrZTlsaXmrbTjgYvjgonorZjliKXjgafjgY3jgZ/lm57nrZTogIXjgavjgaTjgYTjgabjgIHlkITmnaHku7blhoXjgafln7rmupbjgpLntK/nqY3nmoTjgavpgannlKjjgZfjgZ/jgIIiCiAgKQogIAogIG1hbmlwdWxhdGlvbl90YWJsZSA8LSBzY3JlZW5pbmckYXVkaXQgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShhc3NpZ25lZF9jb25kaXRpb24pKSAlPiUKICAgIGRwbHlyOjpjb3VudCgKICAgICAgYXNzaWduZWRfY29uZGl0aW9uLAogICAgICBtYW5pcHVsYXRpb25fcmVzcG9uc2UsCiAgICAgIG1hbmlwdWxhdGlvbl9jaGVja19wYXNzLAogICAgICBuYW1lID0gIm4iCiAgICApICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOadoeS7tmAgPSBhc3NpZ25lZF9jb25kaXRpb24sCiAgICAgIGDlm57nrZRgID0gZHBseXI6OmNvYWxlc2NlKG1hbmlwdWxhdGlvbl9yZXNwb25zZSwgIuacquWun+aWveODu+asoOaQjSIpLAogICAgICBg5q2j562UYCA9IGlmZWxzZShtYW5pcHVsYXRpb25fY2hlY2tfcGFzcywgIuato+etlCIsICLkuI3mraPnrZTjg7vmrKDmkI0iKSwKICAgICAgYE5gID0gZm9ybWF0X2ludGVnZXIobikKICAgICkKICBpZiAoc3R1ZHlfaWQgPT0gInN0dWR5MSIpIHsKICAgIG1hbmlwdWxhdGlvbl90YWJsZSA8LSB0aWJibGU6OnRpYmJsZSgKICAgICAgYOadoeS7tmAgPSAi5YWo5p2h5Lu2IiwKICAgICAgYOWbnuetlGAgPSAi6Kq/5p+756Wo44Gr6YG45oqe6IKi5pWw56K66KqN6LOq5ZWP44Gq44GXIiwKICAgICAgYOato+etlGAgPSAi6YGp55So5aSWIiwKICAgICAgYE5gID0gIiIKICAgICkKICB9CiAgd3JpdGVfY3N2X2FuZF90ZXgoCiAgICBtYW5pcHVsYXRpb25fdGFibGUsCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX21hbmlwdWxhdGlvbl9jaGVjay5jc3YiKSwKICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfbWFuaXB1bGF0aW9uX2NoZWNrLnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya6YG45oqe6IKi5pWw44Gu5pON5L2c56K66KqNIiksCiAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1tYW5pcHVsYXRpb24tY2hlY2siKSwKICAgIG5vdGVzID0gIlN0dWR5IDLjg7sz44Gn44Gv44CB5Ymy44KK5b2T44Gm44KJ44KM44Gf6YG45oqe6IKi5pWw44Go5ZCM44GY5Zue562U44KS5q2j562U44Go44GX44Gf44CCIgogICkKICAKICBhdHRlbnRpb25fdGFibGUgPC0gc2NyZWVuaW5nJGF1ZGl0ICU+JQogICAgZHBseXI6OmNvdW50KGF0dGVudGlvbl9yZXNwb25zZSwgYXR0ZW50aW9uX2NoZWNrX3Bhc3MsIG5hbWUgPSAibiIpICU+JQogICAgZHBseXI6OnRyYW5zbXV0ZSgKICAgICAgYOWbnuetlGAgPSBkcGx5cjo6Y29hbGVzY2UoYXR0ZW50aW9uX3Jlc3BvbnNlLCAi5pyq5a6f5pa944O75qyg5pCNIiksCiAgICAgIGDliKTlrppgID0gaWZlbHNlKGF0dGVudGlvbl9jaGVja19wYXNzLCAi5q2j562UIiwgIuS4jeato+etlOODu+asoOaQjSIpLAogICAgICBgTmAgPSBmb3JtYXRfaW50ZWdlcihuKQogICAgKQogIGlmIChzdHVkeV9pZCA9PSAic3R1ZHkxIikgewogICAgYXR0ZW50aW9uX3RhYmxlIDwtIHRpYmJsZTo6dGliYmxlKAogICAgICBg5Zue562UYCA9ICLoqr/mn7vnpajjgavmjIfnpLrpoIXnm67jgarjgZciLAogICAgICBg5Yik5a6aYCA9ICLpgannlKjlpJYiLAogICAgICBgTmAgPSAiIgogICAgKQogIH0KICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIGF0dGVudGlvbl90YWJsZSwKICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfYXR0ZW50aW9uX2NoZWNrLmNzdiIpLAogICAgZmlsZS5wYXRoKHRleF9kaXIsICJ0YWJsZV9hdHRlbnRpb25fY2hlY2sudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrjgqTjg4fjgqrjg63jgq7jg7zooYzliJfjga7mjIfnpLrpoIXnm64iKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWF0dGVudGlvbi1jaGVjayIpLAogICAgbm90ZXMgPSAiU3R1ZHkgMuODuzPjgafjga/jgIHoqr/mn7vnlLvpnaLkuIrjga7mjIfnpLrpoIXnm67jgafjgIwz44CN44KS6YG45oqe44GX44Gf5Zue562U6ICF44KS5q2j562U44Go44GX44Gf44CCUXVhbHRyaWNz44Gu5L+d5a2Y44Kz44O844OJ44GM6KGo56S65YCk44Go55Ww44Gq44KL5aC05ZCI44Gv44CB5pys5YiG5p6Q44Gn6Ieq5YuV5qSc5Ye644GV44KM44Gf5L+d5a2Y44Kz44O844OJ44KS55So44GE44Gf44CCIgogICkKICAKICBhbWNlX2NvdiA8LSBtYWtlX2FtY2VfdGFibGUoZW52LCBhZGp1c3RlZCA9IFRSVUUpCiAgYW1jZV9ub2NvdiA8LSBtYWtlX2FtY2VfdGFibGUoZW52LCBhZGp1c3RlZCA9IEZBTFNFKQogIGludGVyYWN0aW9uIDwtIG1ha2VfaW50ZXJhY3Rpb25fdGFibGUoZW52KQogIG1tX3RhYmxlIDwtIG1ha2VfbW1fdGFibGUoZW52KQogIGF0dHJfaW1wb3J0YW5jZSA8LSBtYWtlX2F0dHJpYnV0ZV9pbXBvcnRhbmNlX3RhYmxlKGVudikKICBjdWVfaW1wb3J0YW5jZSA8LSBtYWtlX2N1ZV9pbXBvcnRhbmNlX3RhYmxlKGVudikKICBjbG9naXRfdGFibGUgPC0gbWFrZV9jbG9naXRfdGFibGUoZW52KQogIGxpbmVhcl90cmVuZF90YWJsZSA8LSBtYWtlX2xpbmVhcl90cmVuZF90YWJsZShlbnYpCiAgcGFydHlfbWF0Y2hfdGFibGUgPC0gbWFrZV9wYXJ0eV9tYXRjaF90YWJsZShlbnYpCiAgCiAgd3JpdGVfY3N2X2FuZF90ZXgoCiAgICBhbWNlX2NvdiwKICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQuY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX2FtY2VfY292YXJpYXRlX2FkanVzdGVkLnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya5YWx5aSJ6YeP6Kq/5pW05riI44G/QU1DRSIpLAogICAgcGFzdGUwKCJ0YWI6Iiwgc3R1ZHlfaWQsICItYW1jZS1hZGp1c3RlZCIpLAogICAgbm90ZXMgPSAi5o6o5a6a5YCk44Gu5Y2Y5L2N44Gv44OR44O844K744Oz44OI44Od44Kk44Oz44OI44CC5qiZ5rqW6Kqk5beu44Gv5Zue562U6ICF5Y2Y5L2N44Gn44Kv44Op44K544K/5YyW44GX44Gf44CCIgogICkKICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIGFtY2Vfbm9jb3YsCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX2FtY2VfdW5hZGp1c3RlZC5jc3YiKSwKICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfYW1jZV91bmFkanVzdGVkLnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya5YWx5aSJ6YeP44KS5ZCr44KB44Gq44GEQU1DRSIpLAogICAgcGFzdGUwKCJ0YWI6Iiwgc3R1ZHlfaWQsICItYW1jZS11bmFkanVzdGVkIiksCiAgICBub3RlcyA9ICLmjqjlrprlgKTjga7ljZjkvY3jga/jg5Hjg7zjgrvjg7Pjg4jjg53jgqTjg7Pjg4jjgILmqJnmupboqqTlt67jga/lm57nrZTogIXljZjkvY3jgafjgq/jg6njgrnjgr/ljJbjgZfjgZ/jgIIiCiAgKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgaW50ZXJhY3Rpb24sCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX2FtY2VfaW50ZXJhY3Rpb24uY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX2FtY2VfaW50ZXJhY3Rpb24udGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJoy6YG45oqe6IKi5p2h5Lu244Go44Gu5beu44KS6KGo44GZQU1DReS6pOS6kuS9nOeUqCIpLAogICAgcGFzdGUwKCJ0YWI6Iiwgc3R1ZHlfaWQsICItYW1jZS1pbnRlcmFjdGlvbiIpLAogICAgbm90ZXMgPSAi5q2j44Gu5YCk44Gv44CB5b2T6Kmy5p2h5Lu244Gr44GK44GR44KLQU1DReOBjDLpgbjmip7ogqLmnaHku7bjgojjgorlpKfjgY3jgYTjgZPjgajjgpLnpLrjgZnjgIIiCiAgKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgbW1fdGFibGUsCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX21hcmdpbmFsX21lYW5zLmNzdiIpLAogICAgZmlsZS5wYXRoKHRleF9kaXIsICJ0YWJsZV9tYXJnaW5hbF9tZWFucy50ZXgiKSwKICAgIHBhc3RlMChzdHVkeV9sYWJlbCwgIu+8muWxnuaAp+awtOa6luWIpeOBrumZkOeVjOW5s+Wdh++8iE1N77yJIiksCiAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1tYXJnaW5hbC1tZWFucyIpLAogICAgbm90ZXMgPSAi6ZmQ55WM5bmz5Z2H44Gv5b2T6Kmy5rC05rqW44KS44KC44Gk44OX44Ot44OV44Kh44Kk44Or44Gu5bmz5Z2H6YG45oqe56K6546H44CCU0Xjgajkv6HpoLzljLrplpPjga/lm57nrZTogIXjgq/jg6njgrnjgr/jgavlr77lv5zjgZfjgZ/liIfniYfjga7jgb/jga7nt5rlvaLnorrnjofjg6Ljg4fjg6vjgajlkIzlgKTjga7oqIjnrpfjgavjgojjgovjgIIiCiAgKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgYXR0cl9pbXBvcnRhbmNlLAogICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9hdHRyaWJ1dGVfaW1wb3J0YW5jZS5jc3YiKSwKICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfYXR0cmlidXRlX2ltcG9ydGFuY2UudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrlsZ7mgKfliKXjga7mnKroqr/mlbTjg7vpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqYiKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWF0dHJpYnV0ZS1pbXBvcnRhbmNlIiksCiAgICBub3RlcyA9ICLmnKroqr/mlbTph43opoHluqbjga/pmZDnlYzlubPlnYfjga7lhajmsLTmupbjg5rjgqLjga7ntbblr77lt67jga7lubPlnYfjgILoqr/mlbTmuIjjgb/ph43opoHluqbjga/mnKroqr/mlbTph43opoHluqbjgpIx77yP6YG45oqe6IKi5pWw44Gn6Zmk44GX44Gf44CCIgogICkKICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIGN1ZV9pbXBvcnRhbmNlLAogICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9jdWVfaW1wb3J0YW5jZS5jc3YiKSwKICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfY3VlX2ltcG9ydGFuY2UudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrmlL/lhZrjg7vntYzmuIjmiYvjgYzjgYvjgorjga7ph43opoHluqbjgajnm7jlr77mr5Tph40iKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWN1ZS1pbXBvcnRhbmNlIiksCiAgICBub3RlcyA9ICI5NSXkv6HpoLzljLrplpPjga/mnaHku7blhoXjgaflm57nrZTogIXjgpLlvqnlhYPmir3lh7rjgZnjgovjgq/jg6njgrnjgr/jg7vjg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5fjgavjgojjgovjgIIiCiAgKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgY2xvZ2l0X3RhYmxlLAogICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9jb25kaXRpb25hbF9sb2dpdC5jc3YiKSwKICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfY29uZGl0aW9uYWxfbG9naXQudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrmnaHku7bku5jjgY3jg63jgrjjg4Pjg4jmjqjlrpoiKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWNvbmRpdGlvbmFsLWxvZ2l0IiksCiAgICBub3RlcyA9ICLlkITpgbjmip7oqrLpoYzjgpJzdHJhdHVt44Go44GZ44KLTWNGYWRkZW7lnovmnaHku7bku5jjgY3jg63jgrjjg4Pjg4jjgILmqJnmupboqqTlt67jga/lm57nrZTogIXljZjkvY3jgafjgq/jg6njgrnjgr/ljJbjgZfjgZ/jgIIiCiAgKQogIAogIGlmIChucm93KGxpbmVhcl90cmVuZF90YWJsZSkgPiAwKSB7CiAgICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgICAgbGluZWFyX3RyZW5kX3RhYmxlLAogICAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX2FtY2VfbGluZWFyX3RyZW5kLmNzdiIpLAogICAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX2FtY2VfbGluZWFyX3RyZW5kLnRleCIpLAogICAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrpgbjmip7ogqLmlbDjgavlr77jgZnjgotBTUNF44Gu57ea5b2i44OI44Os44Oz44OJIiksCiAgICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWFtY2UtbGluZWFyLXRyZW5kIiksCiAgICAgIG5vdGVzID0gIuS/guaVsOOBr+mBuOaKnuiCouaVsOOBjDHjgaTlopfjgYjjgZ/jgajjgY3jga5BTUNF44Gu5aSJ5YyW44KS44OR44O844K744Oz44OI44Od44Kk44Oz44OI44Gn56S644GZ44CCIgogICAgKQogIH0KICAKICBpZiAobnJvdyhwYXJ0eV9tYXRjaF90YWJsZSkgPiAwKSB7CiAgICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgICAgcGFydHlfbWF0Y2hfdGFibGUsCiAgICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfcGFydHlfbWF0Y2guY3N2IiksCiAgICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfcGFydHlfbWF0Y2gudGV4IiksCiAgICAgIHBhc3RlMChzdHVkeV9sYWJlbCwgIu+8muaUr+aMgeaUv+WFmuOBqOaPkOekuuaUv+WFmuWQjeOBruS4gOiHtOWKueaenCIpLAogICAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1wYXJ0eS1tYXRjaCIpLAogICAgICBub3RlcyA9ICLkuIDoh7Tlirnmnpzjga/jgIHlm57nrZTogIXjga7mlK/mjIHmlL/lhZrjgajmj5DnpLrjgZXjgozjgZ/mlL/lhZrlkI3jgYzkuIDoh7TjgZnjgovjgZPjgajjgavjgojjgovpgbjmip7norrnjoflt67jgIIiCiAgICApCiAgfQogIAogIGJhbGFuY2UgPC0gYXNzaWdubWVudF9iYWxhbmNlX3Jlc3VsdHNbW3N0dWR5X2lkXV0KICBiYWxhbmNlX3N1bW1hcnkgPC0gYmFsYW5jZSRzdW1tYXJ5ICU+JQogICAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IGZvcm1hdF9udW1iZXIoLngsIDMpKSkKICBiYWxhbmNlX3BhaXJ3aXNlIDwtIGJhbGFuY2UkcGFpcndpc2Vfc21kICU+JQogICAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IGZvcm1hdF9udW1iZXIoLngsIDMpKSkKICAKICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIGJhbGFuY2Vfc3VtbWFyeSwKICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfYXNzaWdubWVudF9iYWxhbmNlX3N1bW1hcnkuY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX2Fzc2lnbm1lbnRfYmFsYW5jZV9zdW1tYXJ5LnRleCIpLAogICAgcGFzdGUwKHN0dWR5X2xhYmVsLCAi77ya5p2h5Lu25Yil44Gu5Zue562U6ICF5bGe5oCnIiksCiAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1iYWxhbmNlLXN1bW1hcnkiKSwKICAgIG5vdGVzID0gIkxvdmUgcGxvdOOBiuOCiOOBszQ15bqm57ea6Ki65pat44Gr5a++5b+c44GZ44KL5p2h5Lu25Yil6ZuG6KiI44CCIgogICkKICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIGJhbGFuY2VfcGFpcndpc2UsCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX2Fzc2lnbm1lbnRfYmFsYW5jZV9wYWlyd2lzZV9zbWQuY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX2Fzc2lnbm1lbnRfYmFsYW5jZV9wYWlyd2lzZV9zbWQudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrlhajmnaHku7bjg5rjgqLjga7mqJnmupbljJblubPlnYflt64iKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLWJhbGFuY2Utc21kIiksCiAgICBub3RlcyA9ICLntbblr75TTUTjgYwwLjEw5pyq5rqA44Gn44GC44KM44Gw44CB6YCa5bi444Gv5a6f6LOq55qE44Gr5bCP44GV44GE5LiN5Z2H6KGh44Go6Kej6YeI44GV44KM44KL44CCIgogICkKICByZWFkcjo6d3JpdGVfY3N2KGJhbGFuY2Ukc3VtbWFyeSwgZmlsZS5wYXRoKGRpYWdfYmFsYW5jZV9kaXIsICJhc3NpZ25tZW50X2JhbGFuY2Vfc3VtbWFyeS5jc3YiKSwgbmEgPSAiIikKICByZWFkcjo6d3JpdGVfY3N2KGJhbGFuY2UkcGFpcndpc2Vfc21kLCBmaWxlLnBhdGgoZGlhZ19iYWxhbmNlX2RpciwgImFzc2lnbm1lbnRfYmFsYW5jZV9wYWlyd2lzZV9zbWQuY3N2IiksIG5hID0gIiIpCiAgcmVhZHI6OndyaXRlX2NzdihiYWxhbmNlJGRpYWdvbmFsX2RhdGEsIGZpbGUucGF0aChkaWFnX2JhbGFuY2VfZGlyLCAiYXNzaWdubWVudF9iYWxhbmNlX2RpYWdvbmFsX2RhdGEuY3N2IiksIG5hID0gIiIpCiAgCiAgcmFuZG9taXphdGlvbiA8LSBwcm9maWxlX3JhbmRvbWl6YXRpb25fcmVzdWx0c1tbc3R1ZHlfaWRdXQogIHJhbmRvbV90ZXN0cyA8LSByYW5kb21pemF0aW9uJHVuaWZvcm1pdHlfdGVzdHMgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gZm9ybWF0X251bWJlcigueCwgNCkpKQogIHJhbmRvbV9mcmVxdWVuY3kgPC0gcmFuZG9taXphdGlvbiRmcmVxdWVuY3kgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gZm9ybWF0X251bWJlcigueCwgNCkpKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgcmFuZG9tX3Rlc3RzLAogICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9wcm9maWxlX3JhbmRvbWl6YXRpb25fdGVzdHMuY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX3Byb2ZpbGVfcmFuZG9taXphdGlvbl90ZXN0cy50ZXgiKSwKICAgIHBhc3RlMChzdHVkeV9sYWJlbCwgIu+8muWxnuaAp+awtOa6luaPkOekuuOBruS4gOanmOaAp+aknOWumiIpLAogICAgcGFzdGUwKCJ0YWI6Iiwgc3R1ZHlfaWQsICItcHJvZmlsZS1yYW5kb21pemF0aW9uLXRlc3RzIiksCiAgICBub3RlcyA9ICLlsZ7mgKfDl+adoeS7tuOBlOOBqOOBruOCq+OCpOS6jOS5l+aknOWumuOAgnDlgKTjga9Ib2xt5rOV44Gn44KC6KOc5q2j44GX44Gf44CCIgogICkKICB3cml0ZV9jc3ZfYW5kX3RleCgKICAgIHJhbmRvbV9mcmVxdWVuY3ksCiAgICBmaWxlLnBhdGgoY3N2X2RpciwgInRhYmxlX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9mcmVxdWVuY3kuY3N2IiksCiAgICBmaWxlLnBhdGgodGV4X2RpciwgInRhYmxlX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9mcmVxdWVuY3kudGV4IiksCiAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrlsZ7mgKfmsLTmupbjga7oprPmuKzmr5TnjofjgajoqK3oqIjkuIrjga7mnJ/lvoXmr5TnjociKSwKICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLXByb2ZpbGUtcmFuZG9taXphdGlvbi1mcmVxdWVuY3kiKSwKICAgIG5vdGVzID0gIuWxnuaAp+aPkOekuuOBrjQ15bqm57ea5Zuz44Gr5a++5b+c44GZ44KL5pWw5YCk6KGo44CCIgogICkKICByZWFkcjo6d3JpdGVfY3N2KHJhbmRvbWl6YXRpb24kdW5pZm9ybWl0eV90ZXN0cywgZmlsZS5wYXRoKGRpYWdfcmFuZG9tX2RpciwgInByb2ZpbGVfcmFuZG9taXphdGlvbl90ZXN0cy5jc3YiKSwgbmEgPSAiIikKICByZWFkcjo6d3JpdGVfY3N2KHJhbmRvbWl6YXRpb24kZnJlcXVlbmN5LCBmaWxlLnBhdGgoZGlhZ19yYW5kb21fZGlyLCAicHJvZmlsZV9yYW5kb21pemF0aW9uX2ZyZXF1ZW5jeS5jc3YiKSwgbmEgPSAiIikKICAKICBzdXBwb3J0X2FtY2UgPC0gcGFydHlfc3VwcG9ydF9hbWNlX3Jlc3VsdHNbW3N0dWR5X2lkXV0KICBpZiAoIWlzLm51bGwoc3VwcG9ydF9hbWNlJHN1Ymdyb3VwX2NvZWZmaWNpZW50cykpIHsKICAgIHN1cHBvcnRfYW1jZV90YWJsZSA8LSBzdXBwb3J0X2FtY2Ukc3ViZ3JvdXBfY29lZmZpY2llbnRzICU+JQogICAgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gZm9ybWF0X251bWJlcigueCwgMykpKQogICAgd3JpdGVfY3N2X2FuZF90ZXgoCiAgICAgIHN1cHBvcnRfYW1jZV90YWJsZSwKICAgICAgZmlsZS5wYXRoKGNzdl9kaXIsICJ0YWJsZV9wYXJ0eV9zdXBwb3J0X2FtY2UuY3N2IiksCiAgICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfcGFydHlfc3VwcG9ydF9hbWNlLnRleCIpLAogICAgICBwYXN0ZTAoc3R1ZHlfbGFiZWwsICLvvJrmlK/mjIHmlL/lhZrliKVBTUNFIiksCiAgICAgIHBhc3RlMCgidGFiOiIsIHN0dWR5X2lkLCAiLXBhcnR5LXN1cHBvcnQtYW1jZSIpLAogICAgICBub3RlcyA9ICLmlK/mjIHmlL/lhZrliKVBTUNF5Zuz44Gr5a++5b+c44GZ44KL5o6o5a6a5YCk44CCIgogICAgKQogIH0KICBzdXBwb3J0X3JlbGF0aXZlIDwtIHBhcnR5X3N1cHBvcnRfcmVsYXRpdmVfY3VlX3Jlc3VsdHNbW3N0dWR5X2lkXV0KICBpZiAoIWlzLm51bGwoc3VwcG9ydF9yZWxhdGl2ZSRpbnRlcnZhbHMpKSB7CiAgICBzdXBwb3J0X3JlbGF0aXZlX3RhYmxlIDwtIHN1cHBvcnRfcmVsYXRpdmUkaW50ZXJ2YWxzICU+JQogICAgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gZm9ybWF0X251bWJlcigueCwgMykpKQogICAgd3JpdGVfY3N2X2FuZF90ZXgoCiAgICAgIHN1cHBvcnRfcmVsYXRpdmVfdGFibGUsCiAgICAgIGZpbGUucGF0aChjc3ZfZGlyLCAidGFibGVfcGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWUuY3N2IiksCiAgICAgIGZpbGUucGF0aCh0ZXhfZGlyLCAidGFibGVfcGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWUudGV4IiksCiAgICAgIHBhc3RlMChzdHVkeV9sYWJlbCwgIu+8muaUr+aMgeaUv+WFmuWIpeOBruaJi+OBjOOBi+OCiumHjeimgeW6puOBqOebuOWvvuavlOmHjSIpLAogICAgICBwYXN0ZTAoInRhYjoiLCBzdHVkeV9pZCwgIi1wYXJ0eS1zdXBwb3J0LXJlbGF0aXZlIiksCiAgICAgIG5vdGVzID0gIuaUr+aMgeaUv+WFmuWIpeOBruebuOWvvuavlOmHjeWbs+OBq+WvvuW/nOOBmeOCi+WbnuetlOiAheOCr+ODqeOCueOCv+ODu+ODluODvOODiOOCueODiOODqeODg+ODl+aOqOWumuOAgiIKICAgICkKICB9CiAgCiAgc3R1ZHlfdGFibGVfcGF0aHNbW3N0dWR5X2lkXV0gPC0gbGlzdChjc3ZfZGlyID0gY3N2X2RpciwgdGV4X2RpciA9IHRleF9kaXIpCn0KCgpjcm9zc19jc3ZfZGlyIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfY3Jvc3MsICJ0YWJsZXNfY3N2IikKY3Jvc3NfdGV4X2RpciA8LSBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X2Nyb3NzLCAidGFibGVzX3RleCIpCgpjcm9zc190YWJsZXMgPC0gbGlzdCgKICBoeXBvdGhlc2lzID0gaHlwb3RoZXNpc190ZXN0X3N1bW1hcnksCiAgYWRqdXN0ZWRfc2xvcGVzID0gY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5LAogIGNyb3NzX3JlbGF0aXZlID0gY3Jvc3Nfc3R1ZHlfcmVsYXRpdmVfd2VpZ2h0LAogIGFsbF9wYXJ0eV9tYXRjaF9jb2VmZmljaWVudHMgPSBzdHVkeTNfYWxsX3BhcnR5X21hdGNoX3Jlc3VsdHMkY29lZmZpY2llbnRzLAogIGFsbF9wYXJ0eV9tYXRjaF90cmVuZHMgPSBzdHVkeTNfYWxsX3BhcnR5X21hdGNoX3Jlc3VsdHMkdHJlbmRzCikKCmNyb3NzX2NhcHRpb24gPC0gYygKICBoeXBvdGhlc2lzID0gIjPlrp/pqJPjga7kuLvopoHku67oqqzjgavlr77lv5zjgZnjgovnt5rlvaLlgr7lkJHmpJzlrpoiLAogIGFkanVzdGVkX3Nsb3BlcyA9ICIz5a6f6aiT44Gu6YG45oqe6IKi5pWw6Kq/5pW05riI44G/6YeN6KaB5bqm44Gu57ea5b2i5YK+5ZCRIiwKICBjcm9zc19yZWxhdGl2ZSA9ICIz5a6f6aiT5qiq5pat44Gu5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeNIiwKICBhbGxfcGFydHlfbWF0Y2hfY29lZmZpY2llbnRzID0gIlN0dWR5IDPvvJrjgZnjgbnjgabjga7lr77osaHmlK/mjIHmlL/lhZrjgavjgYrjgZHjgovkuIDoh7TlirnmnpwiLAogIGFsbF9wYXJ0eV9tYXRjaF90cmVuZHMgPSAiU3R1ZHkgM++8muS4gOiHtOWKueaenOOBrumBuOaKnuiCouaVsOODiOODrOODs+ODiSIKKQoKZm9yICh0YWJsZV9uYW1lIGluIG5hbWVzKGNyb3NzX3RhYmxlcykpIHsKICB0YWJsZV9kYXRhIDwtIGNyb3NzX3RhYmxlc1tbdGFibGVfbmFtZV1dCiAgaWYgKGlzLm51bGwodGFibGVfZGF0YSkpIG5leHQKICB0YWJsZV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUodGFibGVfZGF0YSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gZm9ybWF0X251bWJlcigueCwgNCkpKQogIHdyaXRlX2Nzdl9hbmRfdGV4KAogICAgdGFibGVfZGF0YSwKICAgIGZpbGUucGF0aChjcm9zc19jc3ZfZGlyLCBwYXN0ZTAoInRhYmxlXyIsIHRhYmxlX25hbWUsICIuY3N2IikpLAogICAgZmlsZS5wYXRoKGNyb3NzX3RleF9kaXIsIHBhc3RlMCgidGFibGVfIiwgdGFibGVfbmFtZSwgIi50ZXgiKSksCiAgICB1bm5hbWUoY3Jvc3NfY2FwdGlvblt0YWJsZV9uYW1lXSksCiAgICBwYXN0ZTAoInRhYjpjcm9zcy0iLCBnc3ViKCJfIiwgIi0iLCB0YWJsZV9uYW1lKSksCiAgICBub3RlcyA9ICLlr77lv5zjgZnjgovoo5zpgbrlm7Pjga7mlbDlgKTjgpLooajlvaLlvI/jgaflho3mjrLjgZfjgZ/jgIIiCiAgKQp9CgoKZm9yIChzdHVkeV9pZCBpbiBuYW1lcyhzdHVkeV9zcGVjcykpIHsKICB3b3JraW5nX2RpciA8LSB1bmlmaWVkX2NvbmZpZ1tbc3R1ZHlfaWRdXSRvdXRwdXRfZGlyCiAgc3VwcGxlbWVudF9maWdfZGlyIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgc3R1ZHlfaWQsICJmaWd1cmVzIikKICBjb3B5X2ZpbGVzX2J5X3BhdHRlcm4od29ya2luZ19kaXIsIHN1cHBsZW1lbnRfZmlnX2RpciwgIlxcLihwbmd8cGRmKSQiKQogIGNvcHlfZmlsZXNfYnlfcGF0dGVybigKICAgIHdvcmtpbmdfZGlyLAogICAgZmlsZS5wYXRoKGZpbmFsX2RpcnMkbW9kZWxfb2JqZWN0c19yb290LCBzdHVkeV9pZCksCiAgICAiXFwuKHJkc3xSRFMpJCIKICApCiAgY29weV9maWxlc19ieV9wYXR0ZXJuKHdvcmtpbmdfZGlyLCBmaW5hbF9kaXJzJGxvZ3MsICIoc2Vzc2lvbkluZm98XFwudHh0JCkiKQogIAogIHN1cHBvcnRfZGlyIDwtIGZpbGUucGF0aCh1bmlmaWVkX291dHB1dF9kaXIsIHBhc3RlMChzdHVkeV9pZCwgIl9wYXJ0eV9zdXBwb3J0IikpCiAgY29weV9maWxlc19ieV9wYXR0ZXJuKHN1cHBvcnRfZGlyLCBzdXBwbGVtZW50X2ZpZ19kaXIsICJcXC4ocG5nfHBkZikkIikKfQoKY29weV9maWxlc19ieV9wYXR0ZXJuKAogIHVuaWZpZWRfb3V0cHV0X2RpciwKICBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X2Nyb3NzLCAiZmlndXJlcyIpLAogICJcXC4ocG5nfHBkZikkIgopCmNvcHlfZmlsZXNfYnlfcGF0dGVybih1bmlmaWVkX291dHB1dF9kaXIsIGZpbmFsX2RpcnMkbG9ncywgIihzZXNzaW9uSW5mb3xcXC50eHQkKSIpCmNvcHlfZmlsZXNfYnlfcGF0dGVybigKICB1bmlmaWVkX291dHB1dF9kaXIsCiAgZmlsZS5wYXRoKGZpbmFsX2RpcnMkbW9kZWxfb2JqZWN0c19yb290LCAiY3Jvc3Nfc3R1ZHkiKSwKICAiXFwuKHJkc3xSRFMpJCIKKQoKZm9yIChzdHVkeV9pZCBpbiBuYW1lcyhzdHVkeV9zcGVjcykpIHsKICBmb3IgKGtpbmQgaW4gYygiYXNzaWdubWVudF9iYWxhbmNlX2xvdmVfcGxvdCIsICJhc3NpZ25tZW50X2JhbGFuY2VfZGlhZ29uYWxfcGxvdCIpKSB7CiAgICBmb3IgKGV4dGVuc2lvbiBpbiBjKCJwbmciLCAicGRmIikpIHsKICAgICAgc291cmNlIDwtIGZpbGUucGF0aCh1bmlmaWVkX291dHB1dF9kaXIsIHBhc3RlMChzdHVkeV9pZCwgIl8iLCBraW5kLCAiLiIsIGV4dGVuc2lvbikpCiAgICAgIGRlc3RpbmF0aW9uIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJGRpYWdub3N0aWNzX3Jvb3QsIHN0dWR5X2lkLCAiYmFsYW5jZSIsIGJhc2VuYW1lKHNvdXJjZSkpCiAgICAgIGNvcHlfZmlsZV9pZl9leGlzdHMoc291cmNlLCBkZXN0aW5hdGlvbikKICAgIH0KICB9CiAgZm9yIChleHRlbnNpb24gaW4gYygicG5nIiwgInBkZiIpKSB7CiAgICBzb3VyY2UgPC0gZmlsZS5wYXRoKHVuaWZpZWRfb3V0cHV0X2RpciwgcGFzdGUwKHN0dWR5X2lkLCAiX3Byb2ZpbGVfcmFuZG9taXphdGlvbl9kaWFnb25hbF9wbG90LiIsIGV4dGVuc2lvbikpCiAgICBkZXN0aW5hdGlvbiA8LSBmaWxlLnBhdGgoZmluYWxfZGlycyRkaWFnbm9zdGljc19yb290LCBzdHVkeV9pZCwgInJhbmRvbWl6YXRpb24iLCBiYXNlbmFtZShzb3VyY2UpKQogICAgY29weV9maWxlX2lmX2V4aXN0cyhzb3VyY2UsIGRlc3RpbmF0aW9uKQogIH0KfQoKaWYgKGV4aXN0cygibWFpbl90ZXh0X2ZpZ3VyZV9tYW5pZmVzdCIpKSB7CiAgcHVycnI6OnB3YWxrKAogICAgbWFpbl90ZXh0X2ZpZ3VyZV9tYW5pZmVzdCwKICAgIGZ1bmN0aW9uKGZpZ3VyZV9udW1iZXIsIHN0dWR5LCBhbmFseXNpcywgZmlsZV9wbmcsIGZpbGVfcGRmKSB7CiAgICAgIHByZWZpeCA8LSBnc3ViKCJbXkEtWmEtejAtOV0rIiwgIl8iLCBmaWd1cmVfbnVtYmVyKQogICAgICBpZiAoIWlzLm5hKGZpbGVfcG5nKSkgewogICAgICAgIGNvcHlfZmlsZV9pZl9leGlzdHMoCiAgICAgICAgICBmaWxlX3BuZywKICAgICAgICAgIGZpbGUucGF0aChmaW5hbF9kaXJzJG1haW5fZmlndXJlcywgcGFzdGUwKHByZWZpeCwgIl8iLCBiYXNlbmFtZShmaWxlX3BuZykpKQogICAgICAgICkKICAgICAgfQogICAgICBpZiAoIWlzLm5hKGZpbGVfcGRmKSkgewogICAgICAgIGNvcHlfZmlsZV9pZl9leGlzdHMoCiAgICAgICAgICBmaWxlX3BkZiwKICAgICAgICAgIGZpbGUucGF0aChmaW5hbF9kaXJzJG1haW5fZmlndXJlcywgcGFzdGUwKHByZWZpeCwgIl8iLCBiYXNlbmFtZShmaWxlX3BkZikpKQogICAgICAgICkKICAgICAgfQogICAgfQogICkKfQoKbWFpbl90YWJsZV9tYXAgPC0gbGlzdCgKICBzdHVkeTEgPSBjKCJ0YWJsZV9hbWNlX2NvdmFyaWF0ZV9hZGp1c3RlZC50ZXgiLCAidGFibGVfY3VlX2ltcG9ydGFuY2UudGV4IiksCiAgc3R1ZHkyID0gYygidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQudGV4IiwgInRhYmxlX2N1ZV9pbXBvcnRhbmNlLnRleCIpLAogIHN0dWR5MyA9IGMoInRhYmxlX2FtY2VfY292YXJpYXRlX2FkanVzdGVkLnRleCIsICJ0YWJsZV9jdWVfaW1wb3J0YW5jZS50ZXgiLCAidGFibGVfcGFydHlfbWF0Y2gudGV4IikKKQpmb3IgKHN0dWR5X2lkIGluIG5hbWVzKG1haW5fdGFibGVfbWFwKSkgewogIGZvciAodGFibGVfZmlsZSBpbiBtYWluX3RhYmxlX21hcFtbc3R1ZHlfaWRdXSkgewogICAgc291cmNlIDwtIGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgc3R1ZHlfaWQsICJ0YWJsZXNfdGV4IiwgdGFibGVfZmlsZSkKICAgIGNvcHlfZmlsZV9pZl9leGlzdHMoCiAgICAgIHNvdXJjZSwKICAgICAgZmlsZS5wYXRoKGZpbmFsX2RpcnMkbWFpbl90YWJsZXMsIHBhc3RlMChzdHVkeV9pZCwgIl8iLCB0YWJsZV9maWxlKSkKICAgICkKICB9Cn0KCgpwYWlyX21hbmlmZXN0IDwtIHRpYmJsZTo6dHJpYmJsZSgKICB+c3R1ZHlfaWQsIH5zZWN0aW9uX3RpdGxlLCB+ZmlndXJlX2ZpbGUsIH50YWJsZV9maWxlcywKICAic3R1ZHkxIiwgIuWFseWkiemHj+iqv+aVtOa4iOOBv0FNQ0UiLCAiYW1jZV9jb3ZfZmFjZXRfbW9kZWwucG5nIiwgInRhYmxlX2FtY2VfY292YXJpYXRlX2FkanVzdGVkLnRleCIsCiAgInN0dWR5MSIsICJBTUNF44OS44O844OI44Oe44OD44OXIiwgImFtY2VfaGVhdG1hcF9taXhlZF9yYW5rX2NvbG9yZWRfbGFiZWxzLnBuZyIsICJ0YWJsZV9hbWNlX2NvdmFyaWF0ZV9hZGp1c3RlZC50ZXgiLAogICJzdHVkeTEiLCAi5YWx5aSJ6YeP44KS5ZCr44KB44Gq44GEQU1DRSIsICJhbWNlX2ZhY2V0X25vY292LnBuZyIsICJ0YWJsZV9hbWNlX3VuYWRqdXN0ZWQudGV4IiwKICAic3R1ZHkxIiwgIkFNQ0Xjga7mnaHku7blt64iLCAiYW1jZV9pbnRlcmFjdGlvbl9kaWZmZXJlbmNlX2Zyb21fMnBhcnR5LnBuZyIsICJ0YWJsZV9hbWNlX2ludGVyYWN0aW9uLnRleCIsCiAgInN0dWR5MSIsICLmnaHku7bku5jjgY3jg63jgrjjg4Pjg4giLCAiY2xvZ2l0X29kZHNyYXRpb19ub2Nvdi5wbmciLCAidGFibGVfY29uZGl0aW9uYWxfbG9naXQudGV4IiwKICAic3R1ZHkxIiwgIuaJi+OBjOOBi+OCiumHjeimgeW6puOBqOebuOWvvuavlOmHjSIsICJmaWdfc3R1ZHkxX3JlbGF0aXZlX2N1ZV93ZWlnaHRfY2hvaWNlX3NldF9hZGp1c3RlZF9qcF9idy5wbmciLCAidGFibGVfbWFyZ2luYWxfbWVhbnMudGV4O3RhYmxlX2F0dHJpYnV0ZV9pbXBvcnRhbmNlLnRleDt0YWJsZV9jdWVfaW1wb3J0YW5jZS50ZXgiLAogICJzdHVkeTIiLCAi5YWx5aSJ6YeP6Kq/5pW05riI44G/QU1DRSIsICJhbWNlX2Nvdl9mYWNldF9tb2RlbC5wbmciLCAidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQudGV4IiwKICAic3R1ZHkyIiwgIkFNQ0Xjg5Ljg7zjg4jjg57jg4Pjg5ciLCAiYW1jZV9oZWF0bWFwX21peGVkX3JhbmtfY29sb3JlZF9sYWJlbHMucG5nIiwgInRhYmxlX2FtY2VfY292YXJpYXRlX2FkanVzdGVkLnRleCIsCiAgInN0dWR5MiIsICLlhbHlpInph4/jgpLlkKvjgoHjgarjgYRBTUNFIiwgImFtY2VfZmFjZXRfbm9jb3YucG5nIiwgInRhYmxlX2FtY2VfdW5hZGp1c3RlZC50ZXgiLAogICJzdHVkeTIiLCAiQU1DReOBruadoeS7tuW3riIsICJhbWNlX2ludGVyYWN0aW9uX2RpZmZlcmVuY2VfZnJvbV8ycGFydHkucG5nIiwgInRhYmxlX2FtY2VfaW50ZXJhY3Rpb24udGV4IiwKICAic3R1ZHkyIiwgIuadoeS7tuS7mOOBjeODreOCuOODg+ODiCIsICJjbG9naXRfb2Rkc3JhdGlvX25vY292LnBuZyIsICJ0YWJsZV9jb25kaXRpb25hbF9sb2dpdC50ZXgiLAogICJzdHVkeTIiLCAi5omL44GM44GL44KK6YeN6KaB5bqm44Go55u45a++5q+U6YeNIiwgImZpZ19zdHVkeTJfcmVsYXRpdmVfY3VlX3dlaWdodF9jaG9pY2Vfc2V0X2FkanVzdGVkX2pwX2J3LnBuZyIsICJ0YWJsZV9tYXJnaW5hbF9tZWFucy50ZXg7dGFibGVfYXR0cmlidXRlX2ltcG9ydGFuY2UudGV4O3RhYmxlX2N1ZV9pbXBvcnRhbmNlLnRleCIsCiAgInN0dWR5MyIsICLlhbHlpInph4/oqr/mlbTmuIjjgb9BTUNFIiwgImFtY2VfY292X2ZhY2V0X21vZGVsLnBuZyIsICJ0YWJsZV9hbWNlX2NvdmFyaWF0ZV9hZGp1c3RlZC50ZXgiLAogICJzdHVkeTMiLCAi5YWx5aSJ6YeP44KS5ZCr44KB44Gq44GEQU1DRSIsICJhbWNlX25vY292X2ZhY2V0X21vZGVsLnBuZyIsICJ0YWJsZV9hbWNlX3VuYWRqdXN0ZWQudGV4IiwKICAic3R1ZHkzIiwgIkFNQ0Xjga7mnaHku7blt64iLCAiYW1jZV9pbnRlcmFjdGlvbl9kaWZmZXJlbmNlX2Zyb21fMmNob2ljZS5wbmciLCAidGFibGVfYW1jZV9pbnRlcmFjdGlvbi50ZXgiLAogICJzdHVkeTMiLCAiQU1DReOBrue3muW9ouODiOODrOODs+ODiSIsICJhbWNlX2xpbmVhcl90cmVuZC5wbmciLCAidGFibGVfYW1jZV9saW5lYXJfdHJlbmQudGV4IiwKICAic3R1ZHkzIiwgIkFNQ0Xjg5Ljg7zjg4jjg57jg4Pjg5ciLCAiYW1jZV9jb3ZfaGVhdG1hcC5wbmciLCAidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQudGV4IiwKICAic3R1ZHkzIiwgIuadoeS7tuS7mOOBjeODreOCuOODg+ODiCIsICJjbG9naXRfb2Rkc3JhdGlvX25vY292LnBuZyIsICJ0YWJsZV9jb25kaXRpb25hbF9sb2dpdC50ZXgiLAogICJzdHVkeTMiLCAi5pSv5oyB5pS/5YWa44Go5o+Q56S65pS/5YWa5ZCN44Gu5LiA6Ie05Yq55p6cIiwgInBhcnR5X21hdGNoX2VmZmVjdF9jb21iaW5lZC5wbmciLCAidGFibGVfcGFydHlfbWF0Y2gudGV4IiwKICAic3R1ZHkzIiwgIuaJi+OBjOOBi+OCiumHjeimgeW6puOBqOebuOWvvuavlOmHjSIsICJmaWdfc3R1ZHkzX3JlbGF0aXZlX2N1ZV93ZWlnaHRfY2hvaWNlX3NldF9hZGp1c3RlZF9qcF9idy5wbmciLCAidGFibGVfbWFyZ2luYWxfbWVhbnMudGV4O3RhYmxlX2F0dHJpYnV0ZV9pbXBvcnRhbmNlLnRleDt0YWJsZV9jdWVfaW1wb3J0YW5jZS50ZXgiCikKCmZvciAoc3R1ZHlfaWQgaW4gbmFtZXMoc3R1ZHlfc3BlY3MpKSB7CiAgc3VwcG9ydF9maWd1cmVzIDwtIGxpc3QuZmlsZXMoCiAgICBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X3Jvb3QsIHN0dWR5X2lkLCAiZmlndXJlcyIpLAogICAgcGF0dGVybiA9ICJwYXJ0eV9zdXBwb3J0X2FtY2VfLipcXC5wbmckIiwKICAgIGZ1bGwubmFtZXMgPSBGQUxTRQogICkKICBpZiAobGVuZ3RoKHN1cHBvcnRfZmlndXJlcykgPiAwKSB7CiAgICBwYWlyX21hbmlmZXN0IDwtIGRwbHlyOjpiaW5kX3Jvd3MoCiAgICAgIHBhaXJfbWFuaWZlc3QsCiAgICAgIHRpYmJsZTo6dGliYmxlKAogICAgICAgIHN0dWR5X2lkID0gc3R1ZHlfaWQsCiAgICAgICAgc2VjdGlvbl90aXRsZSA9IHBhc3RlMCgi5pSv5oyB5pS/5YWa5YilQU1DRe+8miIsIHN1cHBvcnRfZmlndXJlcyksCiAgICAgICAgZmlndXJlX2ZpbGUgPSBzdXBwb3J0X2ZpZ3VyZXMsCiAgICAgICAgdGFibGVfZmlsZXMgPSAidGFibGVfcGFydHlfc3VwcG9ydF9hbWNlLnRleCIKICAgICAgKQogICAgKQogIH0KICBpZiAoZmlsZS5leGlzdHMoZmlsZS5wYXRoKGZpbmFsX2RpcnMkc3VwcGxlbWVudF9yb290LCBzdHVkeV9pZCwgImZpZ3VyZXMiLCAicGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWVfd2VpZ2h0LnBuZyIpKSkgewogICAgcGFpcl9tYW5pZmVzdCA8LSBkcGx5cjo6YmluZF9yb3dzKAogICAgICBwYWlyX21hbmlmZXN0LAogICAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICBzdHVkeV9pZCA9IHN0dWR5X2lkLAogICAgICAgIHNlY3Rpb25fdGl0bGUgPSAi5pSv5oyB5pS/5YWa5Yil44Gu5omL44GM44GL44KK55u45a++5q+U6YeNIiwKICAgICAgICBmaWd1cmVfZmlsZSA9ICJwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV93ZWlnaHQucG5nIiwKICAgICAgICB0YWJsZV9maWxlcyA9ICJ0YWJsZV9wYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZS50ZXgiCiAgICAgICkKICAgICkKICB9Cn0KCnJlYWRyOjp3cml0ZV9jc3YoCiAgcGFpcl9tYW5pZmVzdCwKICBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X3Jvb3QsICJmaWd1cmVfdGFibGVfcGFpcl9tYW5pZmVzdC5jc3YiKSwKICBuYSA9ICIiCikKCnBhaXJfdGV4X2xpbmVzIDwtIGMoCiAgIiUgR2VuZXJhdGVkIGF1dG9tYXRpY2FsbHkuIFJ1biBMdWFMYVRlWCBmcm9tIHRoZSBzdXBwbGVtZW50IGRpcmVjdG9yeS4iLAogICJcXHByb3ZpZGVjb21tYW5ke1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdH17Ln0iLAogICJcXHNlY3Rpb2575qiZ5pys5qeL56+J44O744OH44O844K/5ZOB6LOq44O75YiG5p6Q57WQ5p6cfSIKKQoKZm9yIChzdHVkeV9pZCBpbiBuYW1lcyhzdHVkeV9zcGVjcykpIHsKICBzdHVkeV9sYWJlbCA8LSBzdHVkeV9zcGVjc1tbc3R1ZHlfaWRdXSRzdHVkeV9sYWJlbAogIHBhaXJfdGV4X2xpbmVzIDwtIGMoCiAgICBwYWlyX3RleF9saW5lcywKICAgIHBhc3RlMCgiXFxzZWN0aW9ueyIsIGxhdGV4X2VzY2FwZShzdHVkeV9sYWJlbCksICJ9IiksCiAgICAiXFxzdWJzZWN0aW9ue+aomeacrOani+evieOBqOOCueOCr+ODquODvOODi+ODs+OCsH0iLAogICAgcGFzdGUwKCJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC8iLCBzdHVkeV9pZCwgIi90YWJsZXNfdGV4L3RhYmxlX3NhbXBsZV9hdHRyaXRpb24udGV4fSIpLAogICAgcGFzdGUwKCJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC8iLCBzdHVkeV9pZCwgIi90YWJsZXNfdGV4L3RhYmxlX3NhbXBsZV9hdHRyaXRpb25fYnlfY29uZGl0aW9uLnRleH0iKSwKICAgIHBhc3RlMCgiXFxpbnB1dHtcXENvbmpvaW50U3VwcGxlbWVudFJvb3QvIiwgc3R1ZHlfaWQsICIvdGFibGVzX3RleC90YWJsZV9tYW5pcHVsYXRpb25fY2hlY2sudGV4fSIpLAogICAgcGFzdGUwKCJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC8iLCBzdHVkeV9pZCwgIi90YWJsZXNfdGV4L3RhYmxlX2F0dGVudGlvbl9jaGVjay50ZXh9IiksCiAgICAiXFxjbGVhcnBhZ2UiLAogICAgIlxcc3Vic2VjdGlvbnvlm57nrZTogIXlibLku5jjga7jg5Djg6njg7Pjgrl9IiwKICAgICJcXGJlZ2lue2ZpZ3VyZX1bcF0iLAogICAgIlxcY2VudGVyaW5nIiwKICAgIHBhc3RlMCgKICAgICAgIlxcaW5jbHVkZWdyYXBoaWNzW3dpZHRoPTAuOTJcXGxpbmV3aWR0aF17XFxDb25qb2ludFN1cHBsZW1lbnRSb290Ly4uL2RpYWdub3N0aWNzLyIsCiAgICAgIHN0dWR5X2lkLAogICAgICAiL2JhbGFuY2UvIiwKICAgICAgc3R1ZHlfaWQsCiAgICAgICJfYXNzaWdubWVudF9iYWxhbmNlX2xvdmVfcGxvdC5wbmd9IgogICAgKSwKICAgIHBhc3RlMCgiXFxjYXB0aW9ueyIsIGxhdGV4X2VzY2FwZShzdHVkeV9sYWJlbCksICLvvJrlm57nrZTogIXlibLku5jjga5Mb3ZlIHBsb3R9IiksCiAgICAiXFxlbmR7ZmlndXJlfSIsCiAgICBwYXN0ZTAoIlxcaW5wdXR7XFxDb25qb2ludFN1cHBsZW1lbnRSb290LyIsIHN0dWR5X2lkLCAiL3RhYmxlc190ZXgvdGFibGVfYXNzaWdubWVudF9iYWxhbmNlX3BhaXJ3aXNlX3NtZC50ZXh9IiksCiAgICAiXFxiZWdpbntmaWd1cmV9W3BdIiwKICAgICJcXGNlbnRlcmluZyIsCiAgICBwYXN0ZTAoCiAgICAgICJcXGluY2x1ZGVncmFwaGljc1t3aWR0aD0wLjkyXFxsaW5ld2lkdGhde1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC8uLi9kaWFnbm9zdGljcy8iLAogICAgICBzdHVkeV9pZCwKICAgICAgIi9iYWxhbmNlLyIsCiAgICAgIHN0dWR5X2lkLAogICAgICAiX2Fzc2lnbm1lbnRfYmFsYW5jZV9kaWFnb25hbF9wbG90LnBuZ30iCiAgICApLAogICAgcGFzdGUwKCJcXGNhcHRpb257IiwgbGF0ZXhfZXNjYXBlKHN0dWR5X2xhYmVsKSwgIu+8muadoeS7tuWIpeWFseWkiemHj+W5s+Wdh+OBrjQ15bqm57ea6Ki65patfSIpLAogICAgIlxcZW5ke2ZpZ3VyZX0iLAogICAgcGFzdGUwKCJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC8iLCBzdHVkeV9pZCwgIi90YWJsZXNfdGV4L3RhYmxlX2Fzc2lnbm1lbnRfYmFsYW5jZV9zdW1tYXJ5LnRleH0iKSwKICAgICJcXGNsZWFycGFnZSIsCiAgICAiXFxzdWJzZWN0aW9ue+OCs+ODs+OCuOODp+OCpOODs+ODiOWxnuaAp+aPkOekuuOBrueEoeS9nOeCuuWMluiouuaWrX0iLAogICAgIlxcYmVnaW57ZmlndXJlfVtwXSIsCiAgICAiXFxjZW50ZXJpbmciLAogICAgcGFzdGUwKAogICAgICAiXFxpbmNsdWRlZ3JhcGhpY3Nbd2lkdGg9MC45MlxcbGluZXdpZHRoXXtcXENvbmpvaW50U3VwcGxlbWVudFJvb3QvLi4vZGlhZ25vc3RpY3MvIiwKICAgICAgc3R1ZHlfaWQsCiAgICAgICIvcmFuZG9taXphdGlvbi8iLAogICAgICBzdHVkeV9pZCwKICAgICAgIl9wcm9maWxlX3JhbmRvbWl6YXRpb25fZGlhZ29uYWxfcGxvdC5wbmd9IgogICAgKSwKICAgIHBhc3RlMCgiXFxjYXB0aW9ueyIsIGxhdGV4X2VzY2FwZShzdHVkeV9sYWJlbCksICLvvJrlsZ7mgKfmsLTmupbjga7oprPmuKzmr5TnjofjgajmnJ/lvoXmr5Tnjod9IiksCiAgICAiXFxlbmR7ZmlndXJlfSIsCiAgICBwYXN0ZTAoIlxcaW5wdXR7XFxDb25qb2ludFN1cHBsZW1lbnRSb290LyIsIHN0dWR5X2lkLCAiL3RhYmxlc190ZXgvdGFibGVfcHJvZmlsZV9yYW5kb21pemF0aW9uX3Rlc3RzLnRleH0iKSwKICAgIHBhc3RlMCgiXFxpbnB1dHtcXENvbmpvaW50U3VwcGxlbWVudFJvb3QvIiwgc3R1ZHlfaWQsICIvdGFibGVzX3RleC90YWJsZV9wcm9maWxlX3JhbmRvbWl6YXRpb25fZnJlcXVlbmN5LnRleH0iKSwKICAgICJcXGNsZWFycGFnZSIsCiAgICAiXFxzdWJzZWN0aW9ue+aOqOWumue1kOaenO+8muWbs+OBqOWvvuW/nOOBmeOCi+ihqH0iCiAgKQogIAogIHN0dWR5X3BhaXJzIDwtIHBhaXJfbWFuaWZlc3QgJT4lIGRwbHlyOjpmaWx0ZXIoLmRhdGEkc3R1ZHlfaWQgPT0gc3R1ZHlfaWQpCiAgZm9yIChpIGluIHNlcV9sZW4obnJvdyhzdHVkeV9wYWlycykpKSB7CiAgICByb3cgPC0gc3R1ZHlfcGFpcnNbaSwgXQogICAgZmlndXJlX3BhdGggPC0gZmlsZS5wYXRoKHJvdyRzdHVkeV9pZCwgImZpZ3VyZXMiLCByb3ckZmlndXJlX2ZpbGUpCiAgICB0YWJsZXMgPC0gdW5saXN0KHN0cnNwbGl0KHJvdyR0YWJsZV9maWxlcywgIjsiLCBmaXhlZCA9IFRSVUUpKQogICAgcGFpcl90ZXhfbGluZXMgPC0gYygKICAgICAgcGFpcl90ZXhfbGluZXMsCiAgICAgIHBhc3RlMCgiXFxzdWJzdWJzZWN0aW9ueyIsIGxhdGV4X2VzY2FwZShyb3ckc2VjdGlvbl90aXRsZSksICJ9IiksCiAgICAgICJcXGJlZ2lue2ZpZ3VyZX1bcF0iLAogICAgICAiXFxjZW50ZXJpbmciLAogICAgICBwYXN0ZTAoIlxcaW5jbHVkZWdyYXBoaWNzW3dpZHRoPTAuOTZcXGxpbmV3aWR0aF17XFxDb25qb2ludFN1cHBsZW1lbnRSb290LyIsIGdzdWIoIlxcXFwiLCAiLyIsIGZpZ3VyZV9wYXRoKSwgIn0iKSwKICAgICAgcGFzdGUwKCJcXGNhcHRpb257IiwgbGF0ZXhfZXNjYXBlKHJvdyRzZWN0aW9uX3RpdGxlKSwgIn0iKSwKICAgICAgIlxcZW5ke2ZpZ3VyZX0iCiAgICApCiAgICBmb3IgKHRhYmxlX2ZpbGUgaW4gdGFibGVzKSB7CiAgICAgIHRhYmxlX3BhdGggPC0gZmlsZS5wYXRoKHJvdyRzdHVkeV9pZCwgInRhYmxlc190ZXgiLCB0YWJsZV9maWxlKQogICAgICBpZiAoZmlsZS5leGlzdHMoZmlsZS5wYXRoKGZpbmFsX2RpcnMkc3VwcGxlbWVudF9yb290LCB0YWJsZV9wYXRoKSkpIHsKICAgICAgICBwYWlyX3RleF9saW5lcyA8LSBjKAogICAgICAgICAgcGFpcl90ZXhfbGluZXMsCiAgICAgICAgICBwYXN0ZTAoIlxcaW5wdXR7XFxDb25qb2ludFN1cHBsZW1lbnRSb290LyIsIGdzdWIoIlxcXFwiLCAiLyIsIHRhYmxlX3BhdGgpLCAifSIpCiAgICAgICAgKQogICAgICB9CiAgICB9CiAgICBwYWlyX3RleF9saW5lcyA8LSBjKHBhaXJfdGV4X2xpbmVzLCAiXFxjbGVhcnBhZ2UiKQogIH0KfQoKcGFpcl90ZXhfbGluZXMgPC0gYygKICBwYWlyX3RleF9saW5lcywKICAiXFxzZWN0aW9uezPlrp/pqJPmqKrmlq3jga7liIbmnpB9IiwKICAiXFxzdWJzZWN0aW9ue+S4u+imgeS7ruiqrOOBrue3muW9ouWCvuWQkeaknOWumn0iLAogICJcXGJlZ2lue2ZpZ3VyZX1bcF0iLAogICJcXGNlbnRlcmluZyIsCiAgIlxcaW5jbHVkZWdyYXBoaWNzW3dpZHRoPTAuOTJcXGxpbmV3aWR0aF17XFxDb25qb2ludFN1cHBsZW1lbnRSb290L2Nyb3NzX3N0dWR5L2ZpZ3VyZXMvZmlnX3N1cHBfaHlwb3RoZXNpc19saW5lYXJfdHJlbmRfdGVzdHMucG5nfSIsCiAgIlxcY2FwdGlvbnsz5a6f6aiT44Gu5Li76KaB5Luu6Kqs44Gr5a++5b+c44GZ44KL57ea5b2i5YK+5ZCR5qSc5a6afSIsCiAgIlxcZW5ke2ZpZ3VyZX0iLAogICJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC9jcm9zc19zdHVkeS90YWJsZXNfdGV4L3RhYmxlX2h5cG90aGVzaXMudGV4fSIsCiAgIlxcY2xlYXJwYWdlIiwKICAiXFxzdWJzZWN0aW9ue+mBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puOBrue3muW9ouWCvuWQkX0iLAogICJcXGJlZ2lue2ZpZ3VyZX1bcF0iLAogICJcXGNlbnRlcmluZyIsCiAgIlxcaW5jbHVkZWdyYXBoaWNzW3dpZHRoPTAuOTJcXGxpbmV3aWR0aF17XFxDb25qb2ludFN1cHBsZW1lbnRSb290L2Nyb3NzX3N0dWR5L2ZpZ3VyZXMvZmlnX3N1cHBfY2hvaWNlX3NldF9hZGp1c3RlZF9pbXBvcnRhbmNlX3Nsb3Blcy5wbmd9IiwKICAiXFxjYXB0aW9uezPlrp/pqJPjga7pgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqbjga7nt5rlvaLlgr7lkJF9IiwKICAiXFxlbmR7ZmlndXJlfSIsCiAgIlxcaW5wdXR7XFxDb25qb2ludFN1cHBsZW1lbnRSb290L2Nyb3NzX3N0dWR5L3RhYmxlc190ZXgvdGFibGVfYWRqdXN0ZWRfc2xvcGVzLnRleH0iLAogICJcXGNsZWFycGFnZSIsCiAgIlxcc3Vic2VjdGlvbnsz5a6f6aiT5qiq5pat44Gu5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeNfSIsCiAgIlxcYmVnaW57ZmlndXJlfVtwXSIsCiAgIlxcY2VudGVyaW5nIiwKICAiXFxpbmNsdWRlZ3JhcGhpY3Nbd2lkdGg9MC45MlxcbGluZXdpZHRoXXtcXENvbmpvaW50U3VwcGxlbWVudFJvb3QvY3Jvc3Nfc3R1ZHkvZmlndXJlcy9maWdfc3VwcF9jcm9zc19zdHVkeV9yZWxhdGl2ZV9wYXJ0eV93ZWlnaHQucG5nfSIsCiAgIlxcY2FwdGlvbnsz5a6f6aiT5qiq5pat44Gu5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeNfSIsCiAgIlxcZW5ke2ZpZ3VyZX0iLAogICJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC9jcm9zc19zdHVkeS90YWJsZXNfdGV4L3RhYmxlX2Nyb3NzX3JlbGF0aXZlLnRleH0iLAogICJcXGNsZWFycGFnZSIKKQoKaWYgKGZpbGUuZXhpc3RzKGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfY3Jvc3MsICJmaWd1cmVzIiwgInBhcnR5X21hdGNoX2FsbF9wYXJ0aWVzLnBuZyIpKSkgewogIHBhaXJfdGV4X2xpbmVzIDwtIGMoCiAgICBwYWlyX3RleF9saW5lcywKICAgICJcXHN1YnNlY3Rpb257U3R1ZHkgM++8muOBmeOBueOBpuOBruWvvuixoeaUr+aMgeaUv+WFmuOBq+OBiuOBkeOCi+S4gOiHtOWKueaenH0iLAogICAgIlxcYmVnaW57ZmlndXJlfVtwXSIsCiAgICAiXFxjZW50ZXJpbmciLAogICAgIlxcaW5jbHVkZWdyYXBoaWNzW3dpZHRoPTAuOTJcXGxpbmV3aWR0aF17XFxDb25qb2ludFN1cHBsZW1lbnRSb290L2Nyb3NzX3N0dWR5L2ZpZ3VyZXMvcGFydHlfbWF0Y2hfYWxsX3BhcnRpZXMucG5nfSIsCiAgICAiXFxjYXB0aW9ue+OBmeOBueOBpuOBruWvvuixoeaUr+aMgeaUv+WFmuOBq+OBiuOBkeOCi+aUr+aMgeaUv+WFmuWQjeS4gOiHtOWKueaenH0iLAogICAgIlxcZW5ke2ZpZ3VyZX0iLAogICAgIlxcaW5wdXR7XFxDb25qb2ludFN1cHBsZW1lbnRSb290L2Nyb3NzX3N0dWR5L3RhYmxlc190ZXgvdGFibGVfYWxsX3BhcnR5X21hdGNoX2NvZWZmaWNpZW50cy50ZXh9IiwKICAgICJcXGlucHV0e1xcQ29uam9pbnRTdXBwbGVtZW50Um9vdC9jcm9zc19zdHVkeS90YWJsZXNfdGV4L3RhYmxlX2FsbF9wYXJ0eV9tYXRjaF90cmVuZHMudGV4fSIsCiAgICAiXFxjbGVhcnBhZ2UiCiAgKQp9Cgp3cml0ZUxpbmVzKAogIHBhaXJfdGV4X2xpbmVzLAogIGNvbiA9IGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgImFsbF9zdHVkaWVzX2ZpZ3VyZV90YWJsZV9wYWlycy50ZXgiKSwKICB1c2VCeXRlcyA9IFRSVUUKKQoKcHJlYW1ibGVfbGluZXMgPC0gYygKICAiJSBBZGQgdGhlc2UgcGFja2FnZXMgdG8gdGhlIHByZWFtYmxlIG9mIGFwcGVuZGl4LnRleC4iLAogICJcXHVzZXBhY2thZ2V7Z3JhcGhpY3h9IiwKICAiXFx1c2VwYWNrYWdle2Jvb2t0YWJzfSIsCiAgIlxcdXNlcGFja2FnZXtsb25ndGFibGV9IiwKICAiXFx1c2VwYWNrYWdle2FycmF5fSIsCiAgIlxcdXNlcGFja2FnZXtwZGZsc2NhcGV9IiwKICAiXFx1c2VwYWNrYWdle2NhcHRpb259IiwKICAiJSBDb21waWxlIHdpdGggTHVhTGFUZVggYmVjYXVzZSB0aGUgZ2VuZXJhdGVkIGNhcHRpb25zIGFuZCB0YWJsZXMgY29udGFpbiBKYXBhbmVzZS4iCikKd3JpdGVMaW5lcygKICBwcmVhbWJsZV9saW5lcywKICBjb24gPSBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X3Jvb3QsICJsYXRleF9wcmVhbWJsZV9zbmlwcGV0LnRleCIpLAogIHVzZUJ5dGVzID0gVFJVRQopCgpzdGFuZGFsb25lX2xpbmVzIDwtIGMoCiAgIiUgIVRlWCBwcm9ncmFtID0gbHVhbGF0ZXgiLAogICJcXGRvY3VtZW50Y2xhc3NbYTRwYXBlciwxMXB0XXtsdGpzYXJ0aWNsZX0iLAogICJcXHVzZXBhY2thZ2VbbWFyZ2luPTIybW1de2dlb21ldHJ5fSIsCiAgIlxcdXNlcGFja2FnZXtncmFwaGljeH0iLAogICJcXHVzZXBhY2thZ2V7Ym9va3RhYnN9IiwKICAiXFx1c2VwYWNrYWdle2xvbmd0YWJsZX0iLAogICJcXHVzZXBhY2thZ2V7YXJyYXl9IiwKICAiXFx1c2VwYWNrYWdle3BkZmxzY2FwZX0iLAogICJcXHVzZXBhY2thZ2V7Y2FwdGlvbn0iLAogICJcXGJlZ2lue2RvY3VtZW50fSIsCiAgIlxcdGFibGVvZmNvbnRlbnRzIiwKICAiXFxjbGVhcnBhZ2UiLAogICJcXGlucHV0e2FsbF9zdHVkaWVzX2ZpZ3VyZV90YWJsZV9wYWlycy50ZXh9IiwKICAiXFxlbmR7ZG9jdW1lbnR9IgopCndyaXRlTGluZXMoCiAgc3RhbmRhbG9uZV9saW5lcywKICBjb24gPSBmaWxlLnBhdGgoZmluYWxfZGlycyRzdXBwbGVtZW50X3Jvb3QsICJzdXBwbGVtZW50X3RhYmxlc19maWd1cmVzX21hc3Rlci50ZXgiKSwKICB1c2VCeXRlcyA9IFRSVUUKKQoKbGF5b3V0X2xpbmVzIDwtIGMoCiAgIk9VVFBVVCBESVJFQ1RPUlkgU1RSVUNUVVJFIiwKICAiPT09PT09PT09PT09PT09PT09PT09PT09PT0iLAogICJtYWluX3RleHQvZmlndXJlcyAgICAgIDogbWFudXNjcmlwdCBmaWd1cmVzIiwKICAibWFpbl90ZXh0L3RhYmxlcyAgICAgICA6IExhVGVYIHRhYmxlcyBjb3JyZXNwb25kaW5nIHRvIG1hbnVzY3JpcHQgZmlndXJlcyIsCiAgInN1cHBsZW1lbnQvc3R1ZHkxLTMgICAgOiBwZXItc3R1ZHkgZmlndXJlcywgQ1NWIHRhYmxlcywgYW5kIExhVGVYIHRhYmxlcyIsCiAgInN1cHBsZW1lbnQvY3Jvc3Nfc3R1ZHkgOiBjcm9zcy1zdHVkeSBmaWd1cmVzIGFuZCB0YWJsZXMiLAogICJkaWFnbm9zdGljcy9zdHVkeTEtMyAgIDogcmVzcG9uZGVudCBzY3JlZW5pbmcsIGJhbGFuY2UsIGFuZCByYW5kb21pemF0aW9uIGRpYWdub3N0aWNzIiwKICAibW9kZWxfb2JqZWN0cyAgICAgICAgICA6IFJEUyBtb2RlbCBhbmQgYW5hbHlzaXMgb2JqZWN0cyIsCiAgImxvZ3MgICAgICAgICAgICAgICAgICAgOiB0ZXh0IG1vZGVsIHN1bW1hcmllcyBhbmQgc2Vzc2lvbiBpbmZvcm1hdGlvbiIsCiAgIl93b3JraW5nICAgICAgICAgICAgICAgOiBvcmlnaW5hbCBpbnRlcm1lZGlhdGUgb3V0cHV0cyBwcm9kdWNlZCBieSBlYWNoIGFuYWx5c2lzIG1vZHVsZSIsCiAgIiIsCiAgIkxBVEVYIiwKICAiLS0tLS0iLAogICJBZGQgdGhlIHBhY2thZ2VzIGluIHN1cHBsZW1lbnQvbGF0ZXhfcHJlYW1ibGVfc25pcHBldC50ZXggdG8gYXBwZW5kaXgudGV4LiIsCiAgIlRoZW4gaW5wdXQgc3VwcGxlbWVudC9hbGxfc3R1ZGllc19maWd1cmVfdGFibGVfcGFpcnMudGV4LCBvciBjb21waWxlIiwKICAic3VwcGxlbWVudC9zdXBwbGVtZW50X3RhYmxlc19maWd1cmVzX21hc3Rlci50ZXggd2l0aCBMdWFMYVRlWC4iCikKd3JpdGVMaW5lcygKICBsYXlvdXRfbGluZXMsCiAgY29uID0gZmlsZS5wYXRoKGZpbmFsX291dHB1dF9yb290LCAiT1VUUFVUX1NUUlVDVFVSRV9BTkRfTEFURVhfUkVBRE1FLnR4dCIpLAogIHVzZUJ5dGVzID0gVFJVRQopCgpzYXZlUkRTKAogIGxpc3QoCiAgICBzY3JlZW5pbmcgPSBzY3JlZW5pbmdfcmVzdWx0cywKICAgIHBhaXJfbWFuaWZlc3QgPSBwYWlyX21hbmlmZXN0LAogICAgZmluYWxfZGlycyA9IGZpbmFsX2RpcnMKICApLAogIGZpbGUgPSBmaWxlLnBhdGgoZmluYWxfZGlycyRtb2RlbF9vYmplY3RzX3Jvb3QsICJzY3JlZW5pbmdfYW5kX2xhdGV4X2V4cG9ydF9vYmplY3RzLnJkcyIpCikKCmNhdCgKICAiXG5TY3JlZW5lZC1zYW1wbGUgYXVkaXQsIExhVGVYIHRhYmxlcywgZmlndXJlLXRhYmxlIHBhaXJzLCBhbmQgZmluYWwgb3V0cHV0IG9yZ2FuaXphdGlvbiBjb21wbGV0ZWQuXG4iLAogICJGaW5hbCBvdXRwdXQgcm9vdDogIiwgbm9ybWFsaXplUGF0aChmaW5hbF9vdXRwdXRfcm9vdCksICJcbiIsCiAgIkxhVGVYIG1hc3RlcjogIiwKICBub3JtYWxpemVQYXRoKGZpbGUucGF0aChmaW5hbF9kaXJzJHN1cHBsZW1lbnRfcm9vdCwgInN1cHBsZW1lbnRfdGFibGVzX2ZpZ3VyZXNfbWFzdGVyLnRleCIpKSwKICAiXG4iLAogIHNlcCA9ICIiCikKYGBgCgojIEIuIOaOqOWumuaWueazleOBqOWIhuaekOaomeacrOOBruWumue+qQoKIyMgQi4xIOWIhuaekOaomeacrAoK5ZCE5Zue562U6ICF44GvMuOAgTPjgIE044CBNeOBruOBhOOBmuOCjOOBi+OBrumBuOaKnuiCouaVsOadoeS7tuOBq+WJsuOCiuW9k+OBpuOCieOCjOOAgTXjgaTjga7pgbjmip7oqrLpoYzjgavlm57nrZTjgZfjgZ/jgILlvpPlsZ7lpInmlbDjga/jgIHlkIToqrLpoYzjgavmj5DnpLrjgZXjgozjgZ/jg5fjg63jg5XjgqPjg7zjg6vjgYzpgbjmip7jgZXjgozjgZ/loLTlkIjjgasx44CB6YG45oqe44GV44KM44Gq44GL44Gj44Gf5aC05ZCI44GrMOOCkuOBqOOCi+S6jOWApOWkieaVsOOBp+OBguOCi+OAggoK5a6f6aiTMeOBp+OBr+OAgeWIneWbnuWQjOaEj+OAgeacgOe1gumAgeS/oeWQjOaEj+OAgeOBiuOCiOOBs+WJsuOCiuW9k+OBpuOCieOCjOOBn+adoeS7tuOBq+OBiuOBkeOCizXoqrLpoYzjga7mnInlirnlm57nrZTjgpLmuoDjgZ/jgZnlm57nrZTogIXjgpLliIbmnpDlr77osaHjgajjgZfjgZ/jgILlrp/pqJMy44O7M+OBp+OBr+OAgeOBk+OCjOOCieOBq+WKoOOBiOOBpuOAgeOCpOODh+OCquODreOCruODvOihjOWIl+S4reOBruaMh+ekuumgheebruOBqOmBuOaKnuiCouaVsOOBruaTjeS9nOeiuuiqjeizquWVj+OBq+ato+etlOOBl+OBn+WbnuetlOiAheOBq+mZkOWumuOBl+OBn+OAggoKIyMgQi4yIEFNQ0UKCuWbnuetlOiAheOCkiAkaSTjgIHpgbjmip7oqrLpoYzjgpIgJHQk44CB44OX44Ot44OV44Kj44O844Or44KSICRqJOOAgemBuOaKnuiCouaVsOadoeS7tuOCkiAkblxpblx7MiwzLDQsNVx9JCDjgajjgZnjgovjgILlvpPlsZ7lpInmlbDjgpIKCiQkCllfe2l0an0KPQpcbWF0aGJmezF9XHtcdGV4dHvjg5fjg63jg5XjgqPjg7zjg6sgfWpcdGV4dHsg44GM6YG45oqe44GV44KM44GffVx9CiQkCgrjgajlrprnvqnjgZnjgovjgILlkITpgbjmip7ogqLmlbDmnaHku7bjgavjgaTjgYTjgabjgIHnt5rlvaLnorrnjofjg6Ljg4fjg6vjgpLliKXjgIXjgavmjqjlrprjgZnjgovjgIIKCiQkCllfe2l0an0KPQpcYWxwaGFfbgorClxzdW1fe2F9ClxzdW1fe1xlbGxcbmVxIFxlbGxfe2EwfX0KXGJldGFfe24sYVxlbGx9RF97aXRqLGFcZWxsfQorClxib2xkc3ltYm9se1xnYW1tYX1fe259XntccHJpbWV9XGJvbGRzeW1ib2x7Wn1fe2l9CisKXHZhcmVwc2lsb25fe2l0an0uCiQkCgokXGJldGFfe24sYVxlbGx9JCDjga/jgIHlsZ7mgKcgJGEkIOOCkuWfuua6luawtOa6liAkXGVsbF97YTB9JCDjgYvjgonmsLTmupYgJFxlbGwkIOOBq+WkieabtOOBl+OBn+OBqOOBjeOBruW5s+Wdh+mZkOeVjOimgee0oOWKueaenO+8iEFNQ0XvvInjgafjgYLjgovjgILmqJnmupboqqTlt67jga/lm57nrZTogIXljZjkvY3jgafjgq/jg6njgrnjgr/ljJbjgZfjgZ/jgIIKCuWun+mokzHjg7sy44Gn44Gv44CB5pS/562W5L2N572u44Gu5Z+65rqW44KS5Lit6YGT44CB5LiO6YeO5YWa5Zyw5L2N44Gu5Z+65rqW44KS6YeO5YWa44CB6K2w5bit5pWw44Gu5Z+65rqW44KSMTDku6XkuIvjgajjgZfjgIFHRFDmiJDplbfnjofjgIHml6XntYzlubPlnYfmoKrkvqHjgIFDUEnjgIHlpLHmpa3njofjga/jgYTjgZrjgozjgoLlpInljJbjgarjgZfjgpLln7rmupbjgajjgZfjgZ/jgILlrp/pqJMz44Gn44Gv5pS/5YWa5ZCN44Gu5Z+65rqW44KS6Ieq55Sx5rCR5Li75YWa44Go44GX44Gf44CCCgoKIyMgQi4zIOmZkOeVjOW5s+Wdh+OBqOWxnuaAp+mHjeimgeW6pgoK6YG45oqe6IKi5pWw5p2h5Lu2ICRuJCDjgavjgYrjgZHjgovlsZ7mgKcgJGEkIOOBruawtOa6liAkXGVsbCQg44Gu6ZmQ55WM5bmz5Z2H44KS44CBCgokJApcd2lkZWhhdHtcbXV9X3tuLGFcZWxsfQo9ClxmcmFjewpcc3VtX3tpLHQsan0KXG1hdGhiZnsxfVx7WF97aXRqLGF9PVxlbGxcfVlfe2l0an0KfXsKXHN1bV97aSx0LGp9ClxtYXRoYmZ7MX1ce1hfe2l0aixhfT1cZWxsXH0KfQokJAoK44Go44GZ44KL44CCCgrlsZ7mgKcgJGEkIOOBjCAkTF9hJCDlgIvjga7msLTmupbjgpLjgoLjgaTjgajjgY3jgIHlsZ7mgKfph43opoHluqbjgpLlhajmsLTmupbjg5rjgqLjga7pmZDnlYzlubPlnYflt67jga7ntbblr77lgKTjga7lubPlnYfjgajjgZfjgabjgIEKCiQkClx3aWRlaGF0e0l9X3tuLGF9Cj0KXGJpbm9te0xfYX17Mn1eey0xfQpcc3VtX3tcZWxsPFxlbGwnfQpcbGVmdHwKXHdpZGVoYXR7XG11fV97bixhXGVsbH0KLQpcd2lkZWhhdHtcbXV9X3tuLGFcZWxsJ30KXHJpZ2h0fAokJAoK44Go5a6a576p44GX44Gf44CCCgrlrp/pqJMx44O7MuOBruaUv+WFmuaJi+OBjOOBi+OCiuOBrumHjeimgeW6puOBr+OAgeaUv+etluS9jee9ruOAgeS4jumHjuWFmuWcsOS9jeOAgeitsOW4reaVsOOBrjPlsZ7mgKfjga7ph43opoHluqbjgpLnrYnjgZfjgYTliqDph43jgaflubPlnYfjgZfjgZ/jgILlrp/pqJMz44Gn44Gv5pS/5YWa5ZCN5bGe5oCn44Gu6YeN6KaB5bqm44KS5pS/5YWa5omL44GM44GL44KK44Gu6YeN6KaB5bqm44Go44GX44Gf44CC57WM5riI5omL44GM44GL44KK44Gv44CBM+Wun+mok+OBqOOCgkdEUOaIkOmVt+eOh+OAgeaXpee1jOW5s+Wdh+agquS+oeOAgUNQSeOAgeWksealreeOh+OBrjTlsZ7mgKfjga7ph43opoHluqbjgpLnrYnjgZfjgYTliqDph43jgaflubPlnYfjgZfjgZ/jgIIKCiMjIEIuNCDpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqbjgajnm7jlr77mr5Tph40KCiRrJCDlgIvjga7jg5fjg63jg5XjgqPjg7zjg6vjgYvjgonlv4XjgZox44Gk44KS6YG45oqe44GZ44KL44Gf44KB44CB44OX44Ot44OV44Kj44O844OrMeS7tuOBguOBn+OCiuOBruW5s+Wdh+mBuOaKnueiuueOh+OBryAkMS9rJCDjgajjgarjgovjgILmnaHku7bplpPmr5TovIPjga7jgZ/jgoHjgIHpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/ph43opoHluqbjgpLjgIEKCiQkClx3aWRlaGF0e0l9XntcbWF0aHJte2Fkan19X3trLGF9Cj0KXGZyYWN7XHdpZGVoYXR7SX1fe2ssYX19ezEva30KPQprXHdpZGVoYXR7SX1fe2ssYX0KJCQKCuOBqOOBl+OBn+OAggoK5pS/5YWa5omL44GM44GL44KK44Gu6YeN6KaB5bqm44KSICRcd2lkZWhhdHtQfV97a30k44CB57WM5riI5omL44GM44GL44KK44Gu6YeN6KaB5bqm44KSICRcd2lkZWhhdHtFfV97a30kIOOBqOOBmeOCi+OBqOOAgeaUv+WFmuaJi+OBjOOBi+OCiuOBruebuOWvvuavlOmHjeOBr+OAgQoKJCQKXHdpZGVoYXR7V31fe2t9Cj0KXGZyYWN7XHdpZGVoYXR7UH1fe2t9fQp7XHdpZGVoYXR7UH1fe2t9K1x3aWRlaGF0e0V9X3trfX0KJCQKCuOBp+OBguOCi+OAguaUv+WFmuODu+e1jOa4iOOBruS4oemHjeimgeW6puOBq+WQjOOBmCAkayQg44KS5LmX44GY44Gm44KC55u45a++5q+U6YeN44Gv5aSJ5YyW44GX44Gq44GE44CCCgojIyBCLjUg44OW44O844OI44K544OI44Op44OD44OX44Go57ea5b2i44OI44Os44Oz44OJCgrph43opoHluqbjgajnm7jlr77mr5Tph43jga45NSXkv6HpoLzljLrplpPjga/jgIHlkITpgbjmip7ogqLmlbDmnaHku7blhoXjgaflm57nrZTogIXjgpLljZjkvY3jgajjgZfjgablvqnlhYPmir3lh7rjgZfjgIHlkITlm57nrZTogIXjga416Kqy6aGM44O75YWo44OX44Ot44OV44Kj44O844Or44Gr5qyg5pCN44Gu44Gq44GE5Zue562U6ICF44Kv44Op44K544K/44O844O744OW44O844OI44K544OI44Op44OD44OX44GL44KJ566X5Ye644GX44Gf44CC5Li76KaB5YiG5p6Q44Gn44GvMiwwMDDlm57lj43lvqnjgZXjgZvjgZ/jgIIKCuWQhOaMh+aomSAkUV9uJCDjga7pgbjmip7ogqLmlbDjgavlr77jgZnjgovnt5rlvaLlgr7lkJHjga/jgIEKCiQkClFfbj1cZXRhK1xkZWx0YSBuK3VfbgokJAoK44Go44GX44GmNOadoeS7tuOBrueCueaOqOWumuWApOOBq09MU+OCkuW9k+OBpuOBr+OCgeOAgeWCvuOBjSAkXGRlbHRhJCDjgpLmsYLjgoHjgZ/jgILlkITjg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5flj43lvqnjgafjgoLlkIzjgZjlgr7jgY3jgpLlho3mjqjlrprjgZfjgIE5NSXkv6HpoLzljLrplpPjgajkuKHlgbTjg5bjg7zjg4jjgrnjg4jjg6njg4Pjg5cgJHAkIOWApOOCkueul+WHuuOBl+OBn+OAgkgxYeOAgUgxYuOAgUgyYeOAgUgyYuOBruWIpOWumuOBq+OBr+mBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puOCkueUqOOBhOOBn+OAggoKIyMgQi42IOadoeS7tuS7mOOBjeODreOCuOODg+ODiAoK5by35Yi26YG45oqe6Kqy6aGM44Gu5qeL6YCg44KS6ICD5oWu44GZ44KL6aCR5YGl5oCn5YiG5p6Q44Go44GX44Gm44CB5ZCE6YG45oqe6IKi5pWw5p2h5Lu244Gr44Gk44GE44Gm5p2h5Lu25LuY44GN44Ot44K444OD44OI44KS5o6o5a6a44GX44Gf44CCCgokJApcUHIoWV97aXRqfT0xXG1pZCBcbWF0aGNhbHtDfV97aXR9KQo9ClxmcmFje1xleHAoXGJvbGRzeW1ib2x7WH1fe2l0an1ee1xwcmltZX1cYm9sZHN5bWJvbHtcYmV0YX0pfQp7XHN1bV97a1xpblxtYXRoY2Fse0N9X3tpdH19XGV4cChcYm9sZHN5bWJvbHtYfV97aXRrfV57XHByaW1lfVxib2xkc3ltYm9se1xiZXRhfSl9LgokJAoK6Kqy6aGM44KS5bGk77yIc3RyYXR1be+8ieOBqOOBl+OAgeWbnuetlOiAheWNmOS9jeOBp+OCr+ODqeOCueOCv+WMluOBl+OBn+OAguWbnuetlOiAheODrOODmeODq+WFseWkiemHj+OBr+WQjOS4gOmBuOaKnuiqsumhjOWGheOBp+S4gOWumuOBp+OBguOCi+OBn+OCgeOAgeadoeS7tuS7mOOBjeODreOCuOODg+ODiOOBq+OBr+ODl+ODreODleOCo+ODvOODq+WxnuaAp+OBruOBv+OCkuaKleWFpeOBl+OBn+OAggoKIyMgQi43IOaUr+aMgeaUv+WFmuWQjeOBqOOBruS4gOiHtOWKueaenAoK5a6f6aiTM+OBp+OBr+OAgQoKJCQKTV97aXRqfQo9ClxtYXRoYmZ7MX1ce1x0ZXh0e+aPkOekuuaUv+WFmuWQjX1fe2l0an09XHRleHR75pSv5oyB5pS/5YWafV97aX1cfQokJAoK44KS5L2c5oiQ44GX44Gf44CC5YWo5L2T44Oi44OH44Or44Gn44Gv44CB5pSv5oyB5pS/5YWa5ZCN5LiA6Ie044CB5o+Q56S65pS/5YWa5ZCN44CBNOOBpOOBrue1jOa4iOWxnuaAp+OCkuaKleWFpeOBl+OAgemBuOaKnuiCouaVsOadoeS7tuOBlOOBqOOBq+aOqOWumuOBl+OBn+OAguOBquOBiuOAgeaUr+aMgeaUv+WFmuWIpeOBruWIhuaekOOBp+OBr+OAgeaUv+WFmuWQjeOBqOS4gOiHtOaMh+aomeOBjOWujOWFqOOBq+WvvuW/nOOBl+OBpuOBl+OBvuOBhuOBn+OCgeOAgeaUv+WFmuWQjeS4u+WKueaenOOCkumZpOOBjeOAgeS4gOiHtOaMh+aomeOBqOe1jOa4iOWxnuaAp+OCkueUqOOBhOOBn+OAggoKIyMgQi44IOODkOODqeODs+OCueOBqOeEoeS9nOeCuuWMluiouuaWrQoK5Zue562U6ICF5Ymy5LuY44Gu44OQ44Op44Oz44K544Gv44CBMuOAgTPjgIE044CBNeadoeS7tuOBruWFqOadoeS7tuODmuOCouOBq+OBpOOBhOOBpuaomea6luWMluW5s+Wdh+W3ruOCkueul+WHuuOBl+OBn+OAgueUqOOBhOOBn+WbnuetlOiAheWxnuaAp+OBr+OAgeWQhOWun+mok+OBp+WIqeeUqOWPr+iDveOBquaAp+WIpeOAgeW5tOm9ouOAgTTlubTliLblpKflrabku6XkuIrjgIHlr77mlbDkuJbluK/lubTlj47jgIHoh6rlt7HjgqTjg4fjgqrjg63jgq7jg7zjgIHjgYrjgojjgbPjgZ3jgozjgonjga7mrKDmkI3mjIfmqJnjgajmlK/mjIHmlL/lhZrjgafjgYLjgovjgILlnLDln5/jg7vpg73pgZPlupznnIzjga/jgZPjga7libLku5jjg5Djg6njg7PjgrnoqLrmlq3jgavjga/nlKjjgYTjgabjgYTjgarjgYTjgIJMb3ZlIHBsb3Qg44Gv5YWoNuadoeS7tuODmuOCouOBrue1tuWvvlNNROOCkuekuuOBl+OAgeWvvuinkue3muWbs+OBr+WQjOOBmOWbnuetlOiAheWFseWkiemHj+OBq+OBpOOBhOOBpuWQhOadoeS7tuW5s+Wdh+OCkuaomea6luWMluOBl+OAgeS6jOadoeS7tuOBmuOBpDQ15bqm57ea44Go5q+U6LyD44GZ44KL6KOc5Yqp55qE44Gq5Y+v6KaW5YyW44Gn44GC44KL44CCCgokJApcbWF0aHJte1NNRH1fe2FifQo9ClxmcmFje1xvdmVybGluZXt4fV9hLVxvdmVybGluZXt4fV9ifQp7XHNxcnR7KHNfYV4yK3NfYl4yKS8yfX0uCiQkCgrjg5fjg63jg5XjgqPjg7zjg6vlsZ7mgKfjga7mj5DnpLrjgavjgaTjgYTjgabjga/jgIHpgbjmip7ogqLmlbDmnaHku7bDl+WxnuaAp8OX5rC05rqW44GU44Go44Gr6Kaz5ris5q+U546H44KS5rGC44KB44CB5rC05rqW5pWw44KSICRMX2EkIOOBqOOBl+OBn+ioreioiOS4iuOBruacn+W+heavlOeOhyAkMS9MX2EkIOOBqOavlOi8g+OBl+OBn+OAguWxnuaAp8OX5p2h5Lu244GU44Go44Gr5LiA5qeY5YiG5biD44KS5biw54Sh5Luu6Kqs44Go44GZ44KL44Kr44Kk5LqM5LmX5qSc5a6a44KS6KGM44GE44CBSG9sbeazleOBq+OCiOOCi+ijnOato+WApOOCguWgseWRiuOBl+OBn+OAggoKCmBgYHtyIGRpc3BsYXktaGVscGVycywgaW5jbHVkZT1GQUxTRX0K5bGe5oCn5pel5pys6KqeIDwtIGZ1bmN0aW9uKHgpIHsKICBkcGx5cjo6Y2FzZV93aGVuKAogICAgeCA9PSAicG9saWN5X3Bvc2l0aW9uIiB+ICLmlL/nrZbkvY3nva4iLAogICAgeCA9PSAiZ292ZXJubWVudF9zdGF0dXMiIH4gIuS4jumHjuWFmuWcsOS9jSIsCiAgICB4ID09ICJzZWF0cyIgfiAi6KGG6K2w6Zmi6K2w5bit5pWwIiwKICAgIHggPT0gImdkcF9ncm93dGgiIH4gIkdEUOaIkOmVt+eOhyIsCiAgICB4ID09ICJuaWtrZWkiIH4gIuaXpee1jOW5s+Wdh+agquS+oSIsCiAgICB4ID09ICJjcGkiIH4gIua2iOiyu+iAheeJqeS+oeaMh+aVsO+8iENQSe+8iSIsCiAgICB4ID09ICJ1bmVtcGxveW1lbnQiIH4gIuWksealreeOhyIsCiAgICB4ID09ICJwYXJ0eV9uYW1lIiB+ICLmlL/lhZrlkI0iLAogICAgVFJVRSB+IGFzLmNoYXJhY3Rlcih4KQogICkKfQoK5p2h5Lu25pel5pys6KqeIDwtIGZ1bmN0aW9uKHgsIHN0dWR5X2lkKSB7CiAgc3VmZml4IDwtIGlmIChzdHVkeV9pZCA9PSAic3R1ZHkzIikgIumBuOaKnuiCouadoeS7tiIgZWxzZSAi5pS/5YWa5p2h5Lu2IgogIHhfY2hyIDwtIGFzLmNoYXJhY3Rlcih4KQogIGRwbHlyOjppZl9lbHNlKAogICAgeF9jaHIgJWluJSBhcy5jaGFyYWN0ZXIoMjo1KSwKICAgIHBhc3RlMCh4X2Nociwgc3VmZml4KSwKICAgIHhfY2hyCiAgKQp9CgrntbHoqIjph4/ml6XmnKzoqp4gPC0gZnVuY3Rpb24oeCwgc3R1ZHlfaWQpIHsKICBwYXJ0eV9uYW1lIDwtIGlmIChzdHVkeV9pZCA9PSAic3R1ZHkzIikgIuaUv+WFmuWQjemHjeimgeW6piIgZWxzZSAi5pS/5YWa6YeN6KaB5bqmIgogIGRwbHlyOjpjYXNlX3doZW4oCiAgICB4ID09ICJwYXJ0eV9pbXBvcnRhbmNlX3BhaXJ3aXNlIiB+IHBhcnR5X25hbWUsCiAgICB4ID09ICJlY29ub21pY19pbXBvcnRhbmNlX3BhaXJ3aXNlIiB+ICLntYzmuIjph43opoHluqYiLAogICAgeCA9PSAicGFydHlfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIgfiBwYXN0ZTAocGFydHlfbmFtZSwgIu+8iOmBuOaKnuiCouaVsOiqv+aVtOa4iOOBv++8iSIpLAogICAgeCA9PSAiZWNvbm9taWNfaW1wb3J0YW5jZV9wYWlyd2lzZV9hZGp1c3RlZCIgfiAi57WM5riI6YeN6KaB5bqm77yI6YG45oqe6IKi5pWw6Kq/5pW05riI44G/77yJIiwKICAgIHggPT0gInJlbGF0aXZlX3BhcnR5X3dlaWdodF9wYWlyd2lzZSIgfiAi5pS/5YWa5omL44GM44GL44KK55u45a++5q+U6YeNIiwKICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoeCkKICApCn0KCuaVsOWApOWIlyA8LSBmdW5jdGlvbih4KSB7CiAgc3VwcHJlc3NXYXJuaW5ncyhyZWFkcjo6cGFyc2VfbnVtYmVyKGFzLmNoYXJhY3Rlcih4KSkpCn0KCuWIl+WQjeaXpeacrOiqniA8LSBmdW5jdGlvbih4KSB7CiAg5a++5b+cIDwtIGMoCiAgICB2YXJpYWJsZSA9ICLlpInmlbAiLAogICAgbGFiZWwgPSAi5rC05rqW44O76KGo56S65ZCNIiwKICAgIHBhcnR5X24gPSAi5p2h5Lu2IiwKICAgIHBhcnR5X25fbGFiZWwgPSAi5p2h5Lu2IiwKICAgIGF0dHJpYnV0ZSA9ICLlsZ7mgKciLAogICAgbGV2ZWwgPSAi5rC05rqWIiwKICAgIHRlcm0gPSAi44Oi44OH44Or6aCFIiwKICAgIGVzdGltYXRlID0gIuaOqOWumuWApCIsCiAgICBgc3RkLmVycm9yYCA9ICLmqJnmupboqqTlt64iLAogICAgc3RhdGlzdGljID0gIuaMh+aomSIsCiAgICBgcC52YWx1ZWAgPSAicOWApCIsCiAgICBgY29uZi5sb3dgID0gIjk1JUNJ5LiL6ZmQIiwKICAgIGBjb25mLmhpZ2hgID0gIjk1JUNJ5LiK6ZmQIiwKICAgIGVzdGltYXRlX3BwID0gIuaOqOWumuWApO+8iHBw77yJIiwKICAgIGNvbmYubG93X3BwID0gIjk1JUNJ5LiL6ZmQ77yIcHDvvIkiLAogICAgY29uZi5oaWdoX3BwID0gIjk1JUNJ5LiK6ZmQ77yIcHDvvIkiLAogICAgbl9pZHMgPSAi5Zue562U6ICF5pWwIiwKICAgIHN0YXR1cyA9ICLmjqjlrprnirbmhYsiLAogICAgb3JkZXIgPSAi6KGo56S66aCGIiwKICAgIHBhcnR5X3N1cHBvcnRfaCA9ICLmlK/mjIHmlL/lhZoiLAogICAgc3VwcG9ydF9wYXJ0eV92YWxpZCA9ICLmlK/mjIHmlL/lhZoiLAogICAgc3R1ZHlfaWQgPSAi5a6f6aiTSUQiLAogICAgc3R1ZHlfbGFiZWwgPSAi5a6f6aiTIiwKICAgIHN0dWR5ID0gIuWun+mokyIsCiAgICBjb21wYXJpc29uID0gIuavlOi8gyIsCiAgICBjb25kaXRpb25fYSA9ICLmnaHku7ZBIiwKICAgIGNvbmRpdGlvbl9iID0gIuadoeS7tkIiLAogICAgbWVhbl9hID0gIuadoeS7tkHlubPlnYciLAogICAgbWVhbl9iID0gIuadoeS7tkLlubPlnYciLAogICAgc2RfYSA9ICLmnaHku7ZB5qiZ5rqW5YGP5beuIiwKICAgIHNkX2IgPSAi5p2h5Lu2Quaomea6luWBj+W3riIsCiAgICBuX2EgPSAi5p2h5Lu2QeWbnuetlOiAheaVsCIsCiAgICBuX2IgPSAi5p2h5Lu2QuWbnuetlOiAheaVsCIsCiAgICBwb29sZWRfc2QgPSAi44OX44O844Or5qiZ5rqW5YGP5beuIiwKICAgIHNtZCA9ICJTTUQiLAogICAgYWJzX3NtZCA9ICJ8U01EfCIsCiAgICBtYXhfYWJzX3NtZCA9ICLmnIDlpKd8U01EfCIsCiAgICBtZWFuX2Fic19zbWQgPSAi5bmz5Z2HfFNNRHwiLAogICAgY2hpX3NxdWFyZSA9ICLjgqvjgqTkuozkuZflgKQiLAogICAgZGYgPSAi6Ieq55Sx5bqmIiwKICAgIHBfdmFsdWUgPSAicOWApCIsCiAgICBwX2hvbG0gPSAiSG9sbeijnOato3DlgKQiLAogICAgb2JzZXJ2ZWRfbiA9ICLoprPmuKzmlbAiLAogICAgdG90YWxfbiA9ICLnt4/mlbAiLAogICAgbl9sZXZlbHMgPSAi5rC05rqW5pWwIiwKICAgIG9ic2VydmVkX3NoYXJlID0gIuims+a4rOavlOeOhyIsCiAgICBleHBlY3RlZF9zaGFyZSA9ICLmnJ/lvoXmr5TnjociLAogICAgZGV2aWF0aW9uID0gIuims+a4rO+8jeacn+W+hSIsCiAgICBhYnNfZGV2aWF0aW9uID0gIue1tuWvvuW3riIsCiAgICBtYXhfYWJzX3NoYXJlX2RldmlhdGlvbiA9ICLmnIDlpKfntbblr77mr5Tnjoflt64iLAogICAgaHlwb3RoZXNpcyA9ICLku67oqqwiLAogICAgZXhwZWN0ZWRfZGlyZWN0aW9uID0gIuS6iOa4rOaWueWQkSIsCiAgICBjb25jbHVzaW9uID0gIuWIpOWumiIsCiAgICBwX3ZhbHVlX3R3b19zaWRlZCA9ICLkuKHlgbRw5YCkIiwKICAgIGN1ZV9mYW1pbHkgPSAi5omL44GM44GL44KK576kIiwKICAgIHN0YXRpc3RpY19sYWJlbCA9ICLmjIfmqJkiLAogICAgYW5hbHlzaXNfcm9sZSA9ICLliIbmnpDkuIrjga7kvY3nva7jgaXjgZEiLAogICAgbWV0cmljX3NjYWxlID0gIuWwuuW6piIsCiAgICBlc3RpbWF0ZV9iYXNlbGluZV9wY3RfcGVyX29wdGlvbiA9ICLlgr7jgY3vvIgl77yJIiwKICAgIGNvbmZfbG93X2Jhc2VsaW5lX3BjdF9wZXJfb3B0aW9uID0gIjk1JUNJ5LiL6ZmQ77yIJe+8iSIsCiAgICBjb25mX2hpZ2hfYmFzZWxpbmVfcGN0X3Blcl9vcHRpb24gPSAiOTUlQ0nkuIrpmZDvvIgl77yJIiwKICAgIGVzdGltYXRlX3BwX3Blcl9vcHRpb24gPSAi5YK+44GN77yIcHDvvIkiLAogICAgY29uZl9sb3dfcHBfcGVyX29wdGlvbiA9ICI5NSVDSeS4i+mZkO+8iHBw77yJIiwKICAgIGNvbmZfaGlnaF9wcF9wZXJfb3B0aW9uID0gIjk1JUNJ5LiK6ZmQ77yIcHDvvIkiLAogICAgZXN0aW1hdGVfcGN0ID0gIuaOqOWumuWApO+8iCXvvIkiLAogICAgY29uZl9sb3dfcGN0ID0gIjk1JUNJ5LiL6ZmQ77yIJe+8iSIsCiAgICBjb25mX2hpZ2hfcGN0ID0gIjk1JUNJ5LiK6ZmQ77yIJe+8iSIKICApCiAgZHBseXI6OmlmX2Vsc2UoeCAlaW4lIG5hbWVzKOWvvuW/nCksIHVubmFtZSjlr77lv5xbeF0pLCB4KQp9Cgrooajml6XmnKzoqp4gPC0gZnVuY3Rpb24oeCkgewogIHggJT4lCiAgICBkcGx5cjo6cmVuYW1lX3dpdGgo5YiX5ZCN5pel5pys6KqeKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIGRwbHlyOjphY3Jvc3MoCiAgICAgICAgZHBseXI6OmV2ZXJ5dGhpbmcoKSwKICAgICAgICB+IGlmIChpcy5udW1lcmljKC54KSkgewogICAgICAgICAgZHBseXI6OmlmX2Vsc2UoaXMubmEoLngpLCAi4oCUIiwgZm9ybWF0KC54LCB0cmltID0gVFJVRSwgc2NpZW50aWZpYyA9IEZBTFNFKSkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpCiAgICAgICAgfQogICAgICApCiAgICApCn0KCuawtOa6luaXpeacrOiqniA8LSBmdW5jdGlvbih0ZXJtLCBsYWJlbCwgYXR0cmlidXRlKSB7CiAgZHBseXI6OmNhc2Vfd2hlbigKICAgIGF0dHJpYnV0ZSA9PSAicG9saWN5X3Bvc2l0aW9uIiB+IHN0cmluZ3I6OnN0cl9yZW1vdmUodGVybSwgIl5wb2xpY3lfcG9zaXRpb24iKSwKICAgIGF0dHJpYnV0ZSA9PSAiZ292ZXJubWVudF9zdGF0dXMiIH4gc3RyaW5ncjo6c3RyX3JlbW92ZSh0ZXJtLCAiXmdvdmVybm1lbnRfc3RhdHVzIiksCiAgICBhdHRyaWJ1dGUgPT0gInNlYXRzIiB+IHN0cmluZ3I6OnN0cl9yZW1vdmUodGVybSwgIl5zZWF0cyIpLAogICAgYXR0cmlidXRlID09ICJnZHBfZ3Jvd3RoIiB+IHBhc3RlMCgiR0RQ77yaIiwgc3RyaW5ncjo6c3RyX3JlbW92ZSh0ZXJtLCAiXmdkcF9ncm93dGhHRFDmiJDplbfnjociKSksCiAgICBhdHRyaWJ1dGUgPT0gIm5pa2tlaSIgfiBwYXN0ZTAoIuaXpee1jOW5s+Wdh++8miIsIHN0cmluZ3I6OnN0cl9yZW1vdmUodGVybSwgIl5uaWtrZWnml6XntYzlubPlnYfliY3mnIjlkIzmnJ/mr5QiKSksCiAgICBhdHRyaWJ1dGUgPT0gImNwaSIgfiBwYXN0ZTAoIkNQSe+8miIsIHN0cmluZ3I6OnN0cl9yZW1vdmUodGVybSwgIl5jcGlDUEnliY3mnJ/mr5QiKSksCiAgICBhdHRyaWJ1dGUgPT0gInVuZW1wbG95bWVudCIgfiBwYXN0ZTAoIuWksealreeOh++8miIsIHN0cmluZ3I6OnN0cl9yZW1vdmUodGVybSwgIl51bmVtcGxveW1lbnTlpLHmpa3njofliY3mnJ/mr5QiKSksCiAgICBhdHRyaWJ1dGUgPT0gInBhcnR5X25hbWUiIH4gc3RyaW5ncjo6c3RyX3JlbW92ZSh0ZXJtLCAiXnBhcnR5X25hbWUiKSwKICAgICFpcy5uYShsYWJlbCkgJiBsYWJlbCAhPSAiIiB+IGFzLmNoYXJhY3RlcihsYWJlbCksCiAgICBUUlVFIH4gYXMuY2hhcmFjdGVyKHRlcm0pCiAgKQp9CmBgYAoKIyBDLiDnhKHkvZzngrrljJbjgavjgaTjgYTjgabjga7lkITnqK7mpJzoqI4KCuS7peS4i+OBp+OAgeWbnuetlOiAheODrOODmeODq+OBruWJsuS7mOODkOODqeODs+OCueOBqOODl+ODreODleOCo+ODvOODq+WxnuaAp+OBrueEoeS9nOeCuuaPkOekuuOBr+WIpeOAheOBq+eiuuiqjeOBmeOCi+OAguWbnuetlOiAheODrOODmeODq+OBp+OBr0xvdmUgcGxvdOOBqDQ15bqm57ea6Ki65pat44KS5L2155So44GX44CB44OX44Ot44OV44Kj44O844Or44Os44OZ44Or44Gn44Gv5ZCE5bGe5oCn5rC05rqW44Gu6Kaz5ris5q+U546H44KS6Kit6KiI5LiK44Gu5pyf5b6F5q+U546H44Go5q+U6LyD44GZ44KL44CCCgoqKkIuMSDlrp/pqJMx77yIMjAyM+W5tO+8iSoqCgojIyDlm7NDMe+8muWbnuetlOiAheWJsuS7mOOBrkxvdmUgcGxvdAoKYGBge3IgYjEtbG92ZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuWun+mokzHku5Xmp5ggPC0gc3R1ZHlfc3BlY3Mkc3R1ZHkxCuWun+mokzHlibLku5joqK3oqIggPC0gbWFrZV9iYWxhbmNlX2Rlc2lnbijlrp/pqJMx5LuV5qeYKQrlrp/pqJMxU01EIDwtIHBhaXJ3aXNlX3NtZF9tdWx0aWFybSjlrp/pqJMx5Ymy5LuY6Kit6KiIJGxvbmcpCuWun+mokzHmnIDlpKdTTUQgPC0g5a6f6aiTMVNNRCAlPiUKICBkcGx5cjo6Z3JvdXBfYnkodmFyaWFibGUsIGxhYmVsKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKG1heF9hYnNfc21kID0gbWF4KGFic19zbWQsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpCgpMb3Zl44OH44O844K/IDwtIOWun+mokzFTTUQgJT4lCiAgZHBseXI6OmxlZnRfam9pbijlrp/pqJMx5pyA5aSnU01ELCBieSA9IGMoInZhcmlhYmxlIiwgImxhYmVsIikpICU+JQogIGRwbHlyOjptdXRhdGUo6KGo56S65ZCNID0gc3RhdHM6OnJlb3JkZXIobGFiZWwsIG1heF9hYnNfc21kKSkKCuWbs0MxIDwtIGdncGxvdDI6OmdncGxvdChMb3Zl44OH44O844K/LCBnZ3Bsb3QyOjphZXMoeCA9IGFic19zbWQsIHkgPSDooajnpLrlkI0pKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4xMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC41NSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoYWxwaGEgPSAwLjMwLCBzaXplID0gMS40LCBwb3NpdGlvbiA9IGdncGxvdDI6OnBvc2l0aW9uX2ppdHRlcihoZWlnaHQgPSAwLjEwLCB3aWR0aCA9IDApKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgIGRhdGEgPSDlrp/pqJMx5pyA5aSnU01EICU+JSBkcGx5cjo6bXV0YXRlKOihqOekuuWQjSA9IHN0YXRzOjpyZW9yZGVyKGxhYmVsLCBtYXhfYWJzX3NtZCkpLAogICAgZ2dwbG90Mjo6YWVzKHggPSBtYXhfYWJzX3NtZCwgeSA9IOihqOekuuWQjSksCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIiwgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMC44CiAgKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIuadoeS7tumWk+OBrue1tuWvvuaomea6luWMluW5s+Wdh+W3ru+8iHxTTUR877yJIiwgeSA9IE5VTEwsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICLlrp/pqJMx77yIMjAyM+W5tO+8ie+8muWQhOeCueOBr+adoeS7tuODmuOCouOAgeeZveaKnOOBjeeCueOBr+acgOWkp+e1tuWvvlNNRCIpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCkpCuWbs0MxCmBgYAoK6KGoQzHjgavjga/lm7NDMeOBruWQhOeCueOBq+WvvuW/nOOBmeOCi+OAguWQhOihjOOBq+OBr+avlOi8g+OBmeOCizLmnaHku7bjga7lubPlnYfjgahTTUTjgpLnpLrjgZnjgIIKCmBgYHtyIGIxLXNtZC10YWJsZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEMxIDwtIOWun+mokzFTTUQgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOWkieaVsCA9IGxhYmVsLAogICAg5q+U6LyDID0gcGFzdGUwKGNvbmRpdGlvbl9hLCAi5pS/5YWa5p2h5Lu277yNIiwgY29uZGl0aW9uX2IsICLmlL/lhZrmnaHku7YiKSwKICAgIGDliY3ogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9hLCAzKSwKICAgIGDlvozogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9iLCAzKSwKICAgIGDliY3ogIVOYCA9IG5fYSwKICAgIGDlvozogIVOYCA9IG5fYiwKICAgIFNNRCA9IHJvdW5kKHNtZCwgMyksCiAgICBgfFNNRHxgID0gcm91bmQoYWJzX3NtZCwgMykKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOWbs0My77ya5p2h5Lu25bmz5Z2H44GuNDXluqbnt5roqLrmlq0KCuWbs0My44Gv5ZuzQzHjgajlkIzjgZjlm57nrZTogIXjg6zjg5njg6vjga7libLku5jjg5Djg6njg7PjgrnjgpLjgIHlkITlhbHlpInph4/jga7mnaHku7blubPlnYfjgpLmqJnmupbljJbjgZfjgZ/jgYbjgYjjgafkuozmnaHku7bjgZrjgaQ0NeW6pue3muOBqOavlOi8g+OBl+OBn+OCguOBruOBp+OBguOCi+OAggoKYGBge3IgYjEtZGlhZ29uYWwsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlr77op5Lnt5rjg4fjg7zjgr8gPC0gYXNzaWdubWVudF9iYWxhbmNlX3Jlc3VsdHMkc3R1ZHkxJGRpYWdvbmFsX2RhdGEgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOavlOi8gyA9IHBhc3RlMChjb25kaXRpb25fYSwgIuaUv+WFmuadoeS7tu+8jSIsIGNvbmRpdGlvbl9iLCAi5pS/5YWa5p2h5Lu2IikKICApCgrjg6njg5njg6vlr77osaEgPC0g5a++6KeS57ea44OH44O844K/ICU+JQogIGRwbHlyOjpncm91cF9ieSjmr5TovIMpICU+JQogIGRwbHlyOjpzbGljZV9tYXgoYWJzX2RpYWdvbmFsX2RldmlhdGlvbiwgbiA9IDMsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6dW5ncm91cCgpCgrou7jnr4Tlm7IgPC0gbWF4KGFicyhjKOWvvuinkue3muODh+ODvOOCvyR4X21lYW4sIOWvvuinkue3muODh+ODvOOCvyR5X21lYW4pKSwgbmEucm0gPSBUUlVFKQrou7jnr4Tlm7IgPC0gbWF4KDAuMTAsIOi7uOevhOWbsiAqIDEuMTUpCgrlm7NDMiA8LSBnZ3Bsb3QyOjpnZ3Bsb3Qo5a++6KeS57ea44OH44O844K/LCBnZ3Bsb3QyOjphZXMoeCA9IHhfbWVhbiwgeSA9IHlfbWVhbikpICsKICBnZ3Bsb3QyOjpnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDAuNjApICsKICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjI1KSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC4yNSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIsIHNpemUgPSAyLjIpICsKICBnZ3Bsb3QyOjpnZW9tX3RleHQoZGF0YSA9IOODqeODmeODq+WvvuixoSwgZ2dwbG90Mjo6YWVzKGxhYmVsID0gbGFiZWwpLCBzaXplID0gMi42LCBjaGVja19vdmVybGFwID0gVFJVRSwgdmp1c3QgPSAtMC43KSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IOavlOi8gywgbmNvbCA9IDMpICsKICBnZ3Bsb3QyOjpjb29yZF9lcXVhbCh4bGltID0gYygt6Lu456+E5ZuyLCDou7jnr4Tlm7IpLCB5bGltID0gYygt6Lu456+E5ZuyLCDou7jnr4Tlm7IpKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIuW3puWBtOadoeS7tuOBruaomea6luWMluWFseWkiemHj+W5s+WdhyIsIHkgPSAi5Y+z5YG05p2h5Lu244Gu5qiZ5rqW5YyW5YWx5aSJ6YeP5bmz5Z2HIikgKwogIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwLjUpICsKICBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpKQrlm7NDMgpgYGAKCmBgYHtyIGIxLWJhbGFuY2Utc3VtbWFyeSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEMyIDwtIGFzc2lnbm1lbnRfYmFsYW5jZV9yZXN1bHRzJHN0dWR5MSRzdW1tYXJ5ICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDlpInmlbAgPSBsYWJlbCwKICAgIGAy5pS/5YWa5p2h5Lu244Gu5bmz5Z2HYCA9IHJvdW5kKG1lYW5fY29uZGl0aW9uXzIsIDMpLAogICAgYDPmlL/lhZrmnaHku7bjga7lubPlnYdgID0gcm91bmQobWVhbl9jb25kaXRpb25fMywgMyksCiAgICBgNOaUv+WFmuadoeS7tuOBruW5s+Wdh2AgPSByb3VuZChtZWFuX2NvbmRpdGlvbl80LCAzKSwKICAgIGA15pS/5YWa5p2h5Lu244Gu5bmz5Z2HYCA9IHJvdW5kKG1lYW5fY29uZGl0aW9uXzUsIDMpLAogICAgYOacgOWkp3xTTUR8YCA9IHJvdW5kKG1heF9hYnNfc21kLCAzKSwKICAgIGBIb2xt6KOc5q2jcOWApGAgPSBzaWduaWYocF9ob2xtLCAzKQogICkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahDMiksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg5ZuzQzPvvJrjg5fjg63jg5XjgqPjg7zjg6vlsZ7mgKfmsLTmupbjga7nhKHkvZzngrrmj5DnpLoKCuWbs0Mz44Gv5Zue562U6ICF44Gu5p2h5Lu25Ymy5LuY44Gn44Gv44Gq44GP44CB5ZCE44Kz44Oz44K444On44Kk44Oz44OI6Kqy6aGM5YaF44Gn5bGe5oCn5rC05rqW44GM6Kit6KiI44Gp44GK44KK5LiA5qeY44Gr5o+Q56S644GV44KM44Gm44GE44KL44GL44KS56K66KqN44GX44Gf44KC44Gu44Gn44GC44KL44CCCgpgYGB7ciBiMS1wcm9maWxlLXJhbmRvbWl6YXRpb24sIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlsZ7mgKfpoLvluqYgPC0gcHJvZmlsZV9yYW5kb21pemF0aW9uX3Jlc3VsdHMkc3R1ZHkxJGZyZXF1ZW5jeSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAg5bGe5oCnID0g5bGe5oCn5pel5pys6KqeKGF0dHJpYnV0ZSksCiAgICDmnaHku7YgPSDmnaHku7bml6XmnKzoqp4ocGFydHlfbiwgInN0dWR5MSIpCiAgKQoK6KGo56S644Op44OZ44OrIDwtIOWxnuaAp+mgu+W6piAlPiUKICBkcGx5cjo6Z3JvdXBfYnko5bGe5oCnLCDmnaHku7YpICU+JQogIGRwbHlyOjpzbGljZV9tYXgoYWJzX2RldmlhdGlvbiwgbiA9IDIsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6dW5ncm91cCgpCgrlm7NDMyA8LSBnZ3Bsb3QyOjpnZ3Bsb3Qo5bGe5oCn6aC75bqmLCBnZ3Bsb3QyOjphZXMoeCA9IGV4cGVjdGVkX3NoYXJlLCB5ID0gb2JzZXJ2ZWRfc2hhcmUsIHNoYXBlID0g5p2h5Lu2KSkgKwogIGdncGxvdDI6Omdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC42NSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoc2l6ZSA9IDIuMiwgZmlsbCA9ICJ3aGl0ZSIpICsKICBnZ3Bsb3QyOjpnZW9tX3RleHQoZGF0YSA9IOihqOekuuODqeODmeODqywgZ2dwbG90Mjo6YWVzKGxhYmVsID0gbGV2ZWwpLCBzaXplID0gMi40LCBjaGVja19vdmVybGFwID0gVFJVRSwgdmp1c3QgPSAtMC43KSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IOWxnuaApywgbmNvbCA9IDMpICsKICBnZ3Bsb3QyOjpjb29yZF9lcXVhbCgpICsKICBnZ3Bsb3QyOjpsYWJzKHggPSAi6Kit6KiI5LiK44Gu5pyf5b6F5q+U546HIiwgeSA9ICLoprPmuKzmr5TnjociLCBzaGFwZSA9ICLmnaHku7YiKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTAuNSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQrlm7NDMwpgYGAKCmBgYHtyIGIxLXJhbmRvbWl6YXRpb24tdGFibGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KGoQzMgPC0gcHJvZmlsZV9yYW5kb21pemF0aW9uX3Jlc3VsdHMkc3R1ZHkxJHVuaWZvcm1pdHlfdGVzdHMgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOadoeS7tiA9IOadoeS7tuaXpeacrOiqnihwYXJ0eV9uLCAic3R1ZHkxIiksCiAgICDlsZ7mgKcgPSDlsZ7mgKfml6XmnKzoqp4oYXR0cmlidXRlKSwKICAgIGDjgqvjgqTkuozkuZflgKRgID0gcm91bmQoY2hpX3NxdWFyZSwgMyksCiAgICDoh6rnlLHluqYgPSBkZiwKICAgIHDlgKQgPSBzaWduaWYocF92YWx1ZSwgMyksCiAgICBgSG9sbeijnOato3DlgKRgID0gc2lnbmlmKHBfaG9sbSwgMyksCiAgICBg5pyA5aSn57W25a++5q+U546H5beuYCA9IHJvdW5kKG1heF9hYnNfc2hhcmVfZGV2aWF0aW9uLCA0KQogICkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahDMyksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCgrooahDNCA8LSDlsZ7mgKfpoLvluqYgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOadoeS7tiwKICAgIOWxnuaApywKICAgIOawtOa6liA9IGxldmVsLAogICAg6Kaz5ris5pWwID0gb2JzZXJ2ZWRfbiwKICAgIOe3j+aVsCA9IHRvdGFsX24sCiAgICDoprPmuKzmr5TnjocgPSByb3VuZChvYnNlcnZlZF9zaGFyZSwgNCksCiAgICDmnJ/lvoXmr5TnjocgPSByb3VuZChleHBlY3RlZF9zaGFyZSwgNCksCiAgICDlt64gPSByb3VuZChkZXZpYXRpb24sIDQpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEM0KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoqKkIuMiDlrp/pqJMy77yIMjAyNuW5tO+8iSoqCgojIyDlm7NDNO+8muWbnuetlOiAheWJsuS7mOOBrkxvdmUgcGxvdAoKYGBge3IgYjItbG92ZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuWun+mokzLku5Xmp5ggPC0gc3R1ZHlfc3BlY3Mkc3R1ZHkyCuWun+mokzLlibLku5joqK3oqIggPC0gbWFrZV9iYWxhbmNlX2Rlc2lnbijlrp/pqJMy5LuV5qeYKQrlrp/pqJMyU01EIDwtIHBhaXJ3aXNlX3NtZF9tdWx0aWFybSjlrp/pqJMy5Ymy5LuY6Kit6KiIJGxvbmcpCuWun+mokzLmnIDlpKdTTUQgPC0g5a6f6aiTMlNNRCAlPiUKICBkcGx5cjo6Z3JvdXBfYnkodmFyaWFibGUsIGxhYmVsKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKG1heF9hYnNfc21kID0gbWF4KGFic19zbWQsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpCgpMb3Zl44OH44O844K/IDwtIOWun+mokzJTTUQgJT4lCiAgZHBseXI6OmxlZnRfam9pbijlrp/pqJMy5pyA5aSnU01ELCBieSA9IGMoInZhcmlhYmxlIiwgImxhYmVsIikpICU+JQogIGRwbHlyOjptdXRhdGUo6KGo56S65ZCNID0gc3RhdHM6OnJlb3JkZXIobGFiZWwsIG1heF9hYnNfc21kKSkKCuWbs0M0IDwtIGdncGxvdDI6OmdncGxvdChMb3Zl44OH44O844K/LCBnZ3Bsb3QyOjphZXMoeCA9IGFic19zbWQsIHkgPSDooajnpLrlkI0pKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4xMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC41NSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoYWxwaGEgPSAwLjMwLCBzaXplID0gMS40LCBwb3NpdGlvbiA9IGdncGxvdDI6OnBvc2l0aW9uX2ppdHRlcihoZWlnaHQgPSAwLjEwLCB3aWR0aCA9IDApKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgKICAgIGRhdGEgPSDlrp/pqJMy5pyA5aSnU01EICU+JSBkcGx5cjo6bXV0YXRlKOihqOekuuWQjSA9IHN0YXRzOjpyZW9yZGVyKGxhYmVsLCBtYXhfYWJzX3NtZCkpLAogICAgZ2dwbG90Mjo6YWVzKHggPSBtYXhfYWJzX3NtZCwgeSA9IOihqOekuuWQjSksCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIiwgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMC44CiAgKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIuadoeS7tumWk+OBrue1tuWvvuaomea6luWMluW5s+Wdh+W3ru+8iHxTTUR877yJIiwgeSA9IE5VTEwsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICLlrp/pqJMy77yIMjAyNuW5tO+8ie+8muWQhOeCueOBr+adoeS7tuODmuOCouOAgeeZveaKnOOBjeeCueOBr+acgOWkp+e1tuWvvlNNRCIpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCkpCuWbs0M0CmBgYAoK6KGoQzXjga/lm7NDNOOBruWQhOeCueOBq+WvvuW/nOOBmeOCi+OAguWQhOihjOOBq+OBr+avlOi8g+OBmeOCizLmnaHku7bjga7lubPlnYfjgahTTUTjgaDjgZHjgpLmrovjgZfjgIHku5bmnaHku7bjgavnlLHmnaXjgZnjgovmp4vpgKDnmoTjgarmrKDmkI3lgKTjga/ooajnpLrjgZfjgarjgYTjgIIKCmBgYHtyIGIyLXNtZC10YWJsZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEM1IDwtIOWun+mokzJTTUQgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOWkieaVsCA9IGxhYmVsLAogICAg5q+U6LyDID0gcGFzdGUwKGNvbmRpdGlvbl9hLCAi5pS/5YWa5p2h5Lu277yNIiwgY29uZGl0aW9uX2IsICLmlL/lhZrmnaHku7YiKSwKICAgIGDliY3ogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9hLCAzKSwKICAgIGDlvozogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9iLCAzKSwKICAgIGDliY3ogIVOYCA9IG5fYSwKICAgIGDlvozogIVOYCA9IG5fYiwKICAgIFNNRCA9IHJvdW5kKHNtZCwgMyksCiAgICBgfFNNRHxgID0gcm91bmQoYWJzX3NtZCwgMykKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzUpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOWbs0M177ya5p2h5Lu25bmz5Z2H44GuNDXluqbnt5roqLrmlq0KCuWbs0M144Gv5ZuzQzTjgajlkIzjgZjlm57nrZTogIXjg6zjg5njg6vjga7libLku5jjg5Djg6njg7PjgrnjgpLjgIHlkITlhbHlpInph4/jga7mnaHku7blubPlnYfjgpLmqJnmupbljJbjgZfjgZ/jgYbjgYjjgacy5p2h5Lu244Ga44GkNDXluqbnt5rjgajmr5TovIPjgZfjgZ/jgoLjga7jgafjgYLjgovjgIIKCmBgYHtyIGIyLWRpYWdvbmFsLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5a++6KeS57ea44OH44O844K/IDwtIGFzc2lnbm1lbnRfYmFsYW5jZV9yZXN1bHRzJHN0dWR5MiRkaWFnb25hbF9kYXRhICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDmr5TovIMgPSBwYXN0ZTAoY29uZGl0aW9uX2EsICLmlL/lhZrmnaHku7bvvI0iLCBjb25kaXRpb25fYiwgIuaUv+WFmuadoeS7tiIpCiAgKQoK44Op44OZ44Or5a++6LGhIDwtIOWvvuinkue3muODh+ODvOOCvyAlPiUKICBkcGx5cjo6Z3JvdXBfYnko5q+U6LyDKSAlPiUKICBkcGx5cjo6c2xpY2VfbWF4KGFic19kaWFnb25hbF9kZXZpYXRpb24sIG4gPSAzLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnVuZ3JvdXAoKQoK6Lu456+E5ZuyIDwtIG1heChhYnMoYyjlr77op5Lnt5rjg4fjg7zjgr8keF9tZWFuLCDlr77op5Lnt5rjg4fjg7zjgr8keV9tZWFuKSksIG5hLnJtID0gVFJVRSkK6Lu456+E5ZuyIDwtIG1heCgwLjEwLCDou7jnr4Tlm7IgKiAxLjE1KQoK5ZuzQzUgPC0gZ2dwbG90Mjo6Z2dwbG90KOWvvuinkue3muODh+ODvOOCvywgZ2dwbG90Mjo6YWVzKHggPSB4X21lYW4sIHkgPSB5X21lYW4pKSArCiAgZ2dwbG90Mjo6Z2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjYwKSArCiAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC4yNSkgKwogIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMjUpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiLCBzaXplID0gMi4yKSArCiAgZ2dwbG90Mjo6Z2VvbV90ZXh0KGRhdGEgPSDjg6njg5njg6vlr77osaEsIGdncGxvdDI6OmFlcyhsYWJlbCA9IGxhYmVsKSwgc2l6ZSA9IDIuNiwgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHZqdXN0ID0gLTAuNykgKwogIGdncGxvdDI6OmZhY2V0X3dyYXAofiDmr5TovIMsIG5jb2wgPSAzKSArCiAgZ2dwbG90Mjo6Y29vcmRfZXF1YWwoeGxpbSA9IGMoLei7uOevhOWbsiwg6Lu456+E5ZuyKSwgeWxpbSA9IGMoLei7uOevhOWbsiwg6Lu456+E5ZuyKSkgKwogIGdncGxvdDI6OmxhYnMoeCA9ICLlt6blgbTmnaHku7bjga7mqJnmupbljJblhbHlpInph4/lubPlnYciLCB5ID0gIuWPs+WBtOadoeS7tuOBruaomea6luWMluWFseWkiemHj+W5s+WdhyIpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMC41KSArCiAgZ2dwbG90Mjo6dGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSkK5ZuzQzUKYGBgCgpgYGB7ciBiMi1iYWxhbmNlLXN1bW1hcnksIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrooahDNiA8LSBhc3NpZ25tZW50X2JhbGFuY2VfcmVzdWx0cyRzdHVkeTIkc3VtbWFyeSAlPiUKICBkcGx5cjo6dHJhbnNtdXRlKAogICAg5aSJ5pWwID0gbGFiZWwsCiAgICBgMuaUv+WFmuadoeS7tuOBruW5s+Wdh2AgPSByb3VuZChtZWFuX2NvbmRpdGlvbl8yLCAzKSwKICAgIGAz5pS/5YWa5p2h5Lu244Gu5bmz5Z2HYCA9IHJvdW5kKG1lYW5fY29uZGl0aW9uXzMsIDMpLAogICAgYDTmlL/lhZrmnaHku7bjga7lubPlnYdgID0gcm91bmQobWVhbl9jb25kaXRpb25fNCwgMyksCiAgICBgNeaUv+WFmuadoeS7tuOBruW5s+Wdh2AgPSByb3VuZChtZWFuX2NvbmRpdGlvbl81LCAzKSwKICAgIGDmnIDlpKd8U01EfGAgPSByb3VuZChtYXhfYWJzX3NtZCwgMyksCiAgICBgSG9sbeijnOato3DlgKRgID0gc2lnbmlmKHBfaG9sbSwgMykKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzYpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOWbs0M277ya44OX44Ot44OV44Kj44O844Or5bGe5oCn5rC05rqW44Gu54Sh5L2c54K65o+Q56S6Cgrlm7NDNuS7pemZjeOBr+WbnuetlOiAheOBruadoeS7tuWJsuS7mOOBp+OBr+OBquOBj+OAgeWQhOOCs+ODs+OCuOODp+OCpOODs+ODiOiqsumhjOWGheOBp+WxnuaAp+awtOa6luOBjOioreioiOOBqeOBiuOCiuS4gOanmOOBq+aPkOekuuOBleOCjOOBpuOBhOOCi+OBi+OCkueiuuiqjeOBmeOCi+OCguOBruOBp+OBguOCi+OAggoKYGBge3IgYjItcHJvZmlsZS1yYW5kb21pemF0aW9uLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5bGe5oCn6aC75bqmIDwtIHByb2ZpbGVfcmFuZG9taXphdGlvbl9yZXN1bHRzJHN0dWR5MiRmcmVxdWVuY3kgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOWxnuaApyA9IOWxnuaAp+aXpeacrOiqnihhdHRyaWJ1dGUpLAogICAg5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKHBhcnR5X24sICJzdHVkeTIiKQogICkKCuihqOekuuODqeODmeODqyA8LSDlsZ7mgKfpoLvluqYgJT4lCiAgZHBseXI6Omdyb3VwX2J5KOWxnuaApywg5p2h5Lu2KSAlPiUKICBkcGx5cjo6c2xpY2VfbWF4KGFic19kZXZpYXRpb24sIG4gPSAyLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnVuZ3JvdXAoKQoK5ZuzQzYgPC0gZ2dwbG90Mjo6Z2dwbG90KOWxnuaAp+mgu+W6piwgZ2dwbG90Mjo6YWVzKHggPSBleHBlY3RlZF9zaGFyZSwgeSA9IG9ic2VydmVkX3NoYXJlLCBzaGFwZSA9IOadoeS7tikpICsKICBnZ3Bsb3QyOjpnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDAuNjUpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHNpemUgPSAyLjIsIGZpbGwgPSAid2hpdGUiKSArCiAgZ2dwbG90Mjo6Z2VvbV90ZXh0KGRhdGEgPSDooajnpLrjg6njg5njg6ssIGdncGxvdDI6OmFlcyhsYWJlbCA9IGxldmVsKSwgc2l6ZSA9IDIuNCwgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHZqdXN0ID0gLTAuNykgKwogIGdncGxvdDI6OmZhY2V0X3dyYXAofiDlsZ7mgKcsIG5jb2wgPSAzKSArCiAgZ2dwbG90Mjo6Y29vcmRfZXF1YWwoKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIuioreioiOS4iuOBruacn+W+heavlOeOhyIsIHkgPSAi6Kaz5ris5q+U546HIiwgc2hhcGUgPSAi5p2h5Lu2IikgKwogIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwLjUpICsKICBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikK5ZuzQzYKYGBgCgpgYGB7ciBiMi1yYW5kb21pemF0aW9uLXRhYmxlcywgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEM3IDwtIHByb2ZpbGVfcmFuZG9taXphdGlvbl9yZXN1bHRzJHN0dWR5MiR1bmlmb3JtaXR5X3Rlc3RzICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDmnaHku7YgPSDmnaHku7bml6XmnKzoqp4ocGFydHlfbiwgInN0dWR5MiIpLAogICAg5bGe5oCnID0g5bGe5oCn5pel5pys6KqeKGF0dHJpYnV0ZSksCiAgICBg44Kr44Kk5LqM5LmX5YCkYCA9IHJvdW5kKGNoaV9zcXVhcmUsIDMpLAogICAg6Ieq55Sx5bqmID0gZGYsCiAgICBw5YCkID0gc2lnbmlmKHBfdmFsdWUsIDMpLAogICAgYEhvbG3oo5zmraNw5YCkYCA9IHNpZ25pZihwX2hvbG0sIDMpLAogICAgYOacgOWkp+e1tuWvvuavlOeOh+W3rmAgPSByb3VuZChtYXhfYWJzX3NoYXJlX2RldmlhdGlvbiwgNCkKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzcpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQoK6KGoQzggPC0g5bGe5oCn6aC75bqmICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDmnaHku7YsCiAgICDlsZ7mgKcsCiAgICDmsLTmupYgPSBsZXZlbCwKICAgIOims+a4rOaVsCA9IG9ic2VydmVkX24sCiAgICDnt4/mlbAgPSB0b3RhbF9uLAogICAg6Kaz5ris5q+U546HID0gcm91bmQob2JzZXJ2ZWRfc2hhcmUsIDQpLAogICAg5pyf5b6F5q+U546HID0gcm91bmQoZXhwZWN0ZWRfc2hhcmUsIDQpLAogICAg5beuID0gcm91bmQoZGV2aWF0aW9uLCA0KQogICkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahDOCksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKKipCLjMg5a6f6aiTM++8iDIwMjblubTvvIkqKgoKIyMg5ZuzQzfvvJrlm57nrZTogIXlibLku5jjga5Mb3ZlIHBsb3QKCmBgYHtyIGIzLWxvdmUsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlrp/pqJMz5LuV5qeYIDwtIHN0dWR5X3NwZWNzJHN0dWR5Mwrlrp/pqJMz5Ymy5LuY6Kit6KiIIDwtIG1ha2VfYmFsYW5jZV9kZXNpZ24o5a6f6aiTM+S7leanmCkK5a6f6aiTM1NNRCA8LSBwYWlyd2lzZV9zbWRfbXVsdGlhcm0o5a6f6aiTM+WJsuS7mOioreioiCRsb25nKQrlrp/pqJMz5pyA5aSnU01EIDwtIOWun+mokzNTTUQgJT4lCiAgZHBseXI6Omdyb3VwX2J5KHZhcmlhYmxlLCBsYWJlbCkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShtYXhfYWJzX3NtZCA9IG1heChhYnNfc21kLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKTG92ZeODh+ODvOOCvyA8LSDlrp/pqJMzU01EICU+JQogIGRwbHlyOjpsZWZ0X2pvaW4o5a6f6aiTM+acgOWkp1NNRCwgYnkgPSBjKCJ2YXJpYWJsZSIsICJsYWJlbCIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKOihqOekuuWQjSA9IHN0YXRzOjpyZW9yZGVyKGxhYmVsLCBtYXhfYWJzX3NtZCkpCgrlm7NDNyA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoTG92ZeODh+ODvOOCvywgZ2dwbG90Mjo6YWVzKHggPSBhYnNfc21kLCB5ID0g6KGo56S65ZCNKSkgKwogIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAuMTAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDAuNTUpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KGFscGhhID0gMC4zMCwgc2l6ZSA9IDEuNCwgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9qaXR0ZXIoaGVpZ2h0ID0gMC4xMCwgd2lkdGggPSAwKSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICBkYXRhID0g5a6f6aiTM+acgOWkp1NNRCAlPiUgZHBseXI6Om11dGF0ZSjooajnpLrlkI0gPSBzdGF0czo6cmVvcmRlcihsYWJlbCwgbWF4X2Fic19zbWQpKSwKICAgIGdncGxvdDI6OmFlcyh4ID0gbWF4X2Fic19zbWQsIHkgPSDooajnpLrlkI0pLAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIsIHNpemUgPSAyLjUsIHN0cm9rZSA9IDAuOAogICkgKwogIGdncGxvdDI6OmxhYnMoeCA9ICLmnaHku7bplpPjga7ntbblr77mqJnmupbljJblubPlnYflt67vvIh8U01EfO+8iSIsIHkgPSBOVUxMLAogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAi5a6f6aiTM++8iDIwMjblubTvvInvvJrlkITngrnjga/mnaHku7bjg5rjgqLjgIHnmb3mipzjgY3ngrnjga/mnIDlpKfntbblr75TTUQiKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTEpICsKICBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpKQrlm7NDNwpgYGAKCuihqEM544Gv5ZuzQzfjga7lkITngrnjgavlr77lv5zjgZnjgovjgIIKCmBgYHtyIGIzLXNtZC10YWJsZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEM5IDwtIOWun+mokzNTTUQgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOWkieaVsCA9IGxhYmVsLAogICAg5q+U6LyDID0gcGFzdGUwKGNvbmRpdGlvbl9hLCAi6YG45oqe6IKi5p2h5Lu277yNIiwgY29uZGl0aW9uX2IsICLpgbjmip7ogqLmnaHku7YiKSwKICAgIGDliY3ogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9hLCAzKSwKICAgIGDlvozogIXjga7lubPlnYdgID0gcm91bmQobWVhbl9iLCAzKSwKICAgIGDliY3ogIVOYCA9IG5fYSwKICAgIGDlvozogIVOYCA9IG5fYiwKICAgIFNNRCA9IHJvdW5kKHNtZCwgMyksCiAgICBgfFNNRHxgID0gcm91bmQoYWJzX3NtZCwgMykKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzkpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOWbs0M477ya5p2h5Lu25bmz5Z2H44GuNDXluqbnt5roqLrmlq0KCuWbs0M444Gv5ZuzQzfjgajlkIzjgZjlm57nrZTogIXjg6zjg5njg6vjga7libLku5jjg5Djg6njg7PjgrnjgpLjgIHlkITlhbHlpInph4/jga7mnaHku7blubPlnYfjgpLmqJnmupbljJbjgZfjgZ/jgYbjgYjjgacy5p2h5Lu244Ga44GkNDXluqbnt5rjgajmr5TovIPjgZfjgZ/jgoLjga7jgafjgYLjgovjgIIKCmBgYHtyIGIzLWRpYWdvbmFsLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5a++6KeS57ea44OH44O844K/IDwtIGFzc2lnbm1lbnRfYmFsYW5jZV9yZXN1bHRzJHN0dWR5MyRkaWFnb25hbF9kYXRhICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDmr5TovIMgPSBwYXN0ZTAoY29uZGl0aW9uX2EsICLpgbjmip7ogqLmnaHku7bvvI0iLCBjb25kaXRpb25fYiwgIumBuOaKnuiCouadoeS7tiIpCiAgKQoK44Op44OZ44Or5a++6LGhIDwtIOWvvuinkue3muODh+ODvOOCvyAlPiUKICBkcGx5cjo6Z3JvdXBfYnko5q+U6LyDKSAlPiUKICBkcGx5cjo6c2xpY2VfbWF4KGFic19kaWFnb25hbF9kZXZpYXRpb24sIG4gPSAzLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnVuZ3JvdXAoKQoK6Lu456+E5ZuyIDwtIG1heChhYnMoYyjlr77op5Lnt5rjg4fjg7zjgr8keF9tZWFuLCDlr77op5Lnt5rjg4fjg7zjgr8keV9tZWFuKSksIG5hLnJtID0gVFJVRSkK6Lu456+E5ZuyIDwtIG1heCgwLjEwLCDou7jnr4Tlm7IgKiAxLjE1KQoK5ZuzQzggPC0gZ2dwbG90Mjo6Z2dwbG90KOWvvuinkue3muODh+ODvOOCvywgZ2dwbG90Mjo6YWVzKHggPSB4X21lYW4sIHkgPSB5X21lYW4pKSArCiAgZ2dwbG90Mjo6Z2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjYwKSArCiAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC4yNSkgKwogIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuMjUpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiLCBzaXplID0gMi4yKSArCiAgZ2dwbG90Mjo6Z2VvbV90ZXh0KGRhdGEgPSDjg6njg5njg6vlr77osaEsIGdncGxvdDI6OmFlcyhsYWJlbCA9IGxhYmVsKSwgc2l6ZSA9IDIuNiwgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHZqdXN0ID0gLTAuNykgKwogIGdncGxvdDI6OmZhY2V0X3dyYXAofiDmr5TovIMsIG5jb2wgPSAzKSArCiAgZ2dwbG90Mjo6Y29vcmRfZXF1YWwoeGxpbSA9IGMoLei7uOevhOWbsiwg6Lu456+E5ZuyKSwgeWxpbSA9IGMoLei7uOevhOWbsiwg6Lu456+E5ZuyKSkgKwogIGdncGxvdDI6OmxhYnMoeCA9ICLlt6blgbTmnaHku7bjga7mqJnmupbljJblhbHlpInph4/lubPlnYciLCB5ID0gIuWPs+WBtOadoeS7tuOBruaomea6luWMluWFseWkiemHj+W5s+WdhyIpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMC41KSArCiAgZ2dwbG90Mjo6dGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSkK5ZuzQzgKYGBgCgpgYGB7ciBiMy1iYWxhbmNlLXN1bW1hcnksIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrooahDMTAgPC0gYXNzaWdubWVudF9iYWxhbmNlX3Jlc3VsdHMkc3R1ZHkzJHN1bW1hcnkgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOWkieaVsCA9IGxhYmVsLAogICAgYDLpgbjmip7ogqLmnaHku7bjga7lubPlnYdgID0gcm91bmQobWVhbl9jb25kaXRpb25fMiwgMyksCiAgICBgM+mBuOaKnuiCouadoeS7tuOBruW5s+Wdh2AgPSByb3VuZChtZWFuX2NvbmRpdGlvbl8zLCAzKSwKICAgIGA06YG45oqe6IKi5p2h5Lu244Gu5bmz5Z2HYCA9IHJvdW5kKG1lYW5fY29uZGl0aW9uXzQsIDMpLAogICAgYDXpgbjmip7ogqLmnaHku7bjga7lubPlnYdgID0gcm91bmQobWVhbl9jb25kaXRpb25fNSwgMyksCiAgICBg5pyA5aSnfFNNRHxgID0gcm91bmQobWF4X2Fic19zbWQsIDMpLAogICAgYEhvbG3oo5zmraNw5YCkYCA9IHNpZ25pZihwX2hvbG0sIDMpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEMxMCksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg5ZuzQznvvJrjg5fjg63jg5XjgqPjg7zjg6vlsZ7mgKfmsLTmupbjga7nhKHkvZzngrrmj5DnpLoKCuWbs0M544Gv5Zue562U6ICF44Gu5p2h5Lu25Ymy5LuY44Gn44Gv44Gq44GP44CB5ZCE44Kz44Oz44K444On44Kk44Oz44OI6Kqy6aGM5YaF44Gn5bGe5oCn5rC05rqW44GM6Kit6KiI44Gp44GK44KK5LiA5qeY44Gr5o+Q56S644GV44KM44Gm44GE44KL44GL44KS56K66KqN44GZ44KL44KC44Gu44Gn44GC44KL44CCCgpgYGB7ciBiMy1wcm9maWxlLXJhbmRvbWl6YXRpb24sIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlsZ7mgKfpoLvluqYgPC0gcHJvZmlsZV9yYW5kb21pemF0aW9uX3Jlc3VsdHMkc3R1ZHkzJGZyZXF1ZW5jeSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAg5bGe5oCnID0g5bGe5oCn5pel5pys6KqeKGF0dHJpYnV0ZSksCiAgICDmnaHku7YgPSDmnaHku7bml6XmnKzoqp4ocGFydHlfbiwgInN0dWR5MyIpCiAgKQoK6KGo56S644Op44OZ44OrIDwtIOWxnuaAp+mgu+W6piAlPiUKICBkcGx5cjo6Z3JvdXBfYnko5bGe5oCnLCDmnaHku7YpICU+JQogIGRwbHlyOjpzbGljZV9tYXgoYWJzX2RldmlhdGlvbiwgbiA9IDIsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6dW5ncm91cCgpCgrlm7NDOSA8LSBnZ3Bsb3QyOjpnZ3Bsb3Qo5bGe5oCn6aC75bqmLCBnZ3Bsb3QyOjphZXMoeCA9IGV4cGVjdGVkX3NoYXJlLCB5ID0gb2JzZXJ2ZWRfc2hhcmUsIHNoYXBlID0g5p2h5Lu2KSkgKwogIGdncGxvdDI6Omdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC42NSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoc2l6ZSA9IDIuMiwgZmlsbCA9ICJ3aGl0ZSIpICsKICBnZ3Bsb3QyOjpnZW9tX3RleHQoZGF0YSA9IOihqOekuuODqeODmeODqywgZ2dwbG90Mjo6YWVzKGxhYmVsID0gbGV2ZWwpLCBzaXplID0gMi40LCBjaGVja19vdmVybGFwID0gVFJVRSwgdmp1c3QgPSAtMC43KSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IOWxnuaApywgbmNvbCA9IDMpICsKICBnZ3Bsb3QyOjpjb29yZF9lcXVhbCgpICsKICBnZ3Bsb3QyOjpsYWJzKHggPSAi6Kit6KiI5LiK44Gu5pyf5b6F5q+U546HIiwgeSA9ICLoprPmuKzmr5TnjociLCBzaGFwZSA9ICLmnaHku7YiKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTAuNSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQrlm7NDOQpgYGAKCmBgYHtyIGIzLXJhbmRvbWl6YXRpb24tdGFibGVzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KGoQzExIDwtIHByb2ZpbGVfcmFuZG9taXphdGlvbl9yZXN1bHRzJHN0dWR5MyR1bmlmb3JtaXR5X3Rlc3RzICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDmnaHku7YgPSDmnaHku7bml6XmnKzoqp4ocGFydHlfbiwgInN0dWR5MyIpLAogICAg5bGe5oCnID0g5bGe5oCn5pel5pys6KqeKGF0dHJpYnV0ZSksCiAgICBg44Kr44Kk5LqM5LmX5YCkYCA9IHJvdW5kKGNoaV9zcXVhcmUsIDMpLAogICAg6Ieq55Sx5bqmID0gZGYsCiAgICBw5YCkID0gc2lnbmlmKHBfdmFsdWUsIDMpLAogICAgYEhvbG3oo5zmraNw5YCkYCA9IHNpZ25pZihwX2hvbG0sIDMpLAogICAgYOacgOWkp+e1tuWvvuavlOeOh+W3rmAgPSByb3VuZChtYXhfYWJzX3NoYXJlX2RldmlhdGlvbiwgNCkKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoQzExKSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKCuihqEMxMiA8LSDlsZ7mgKfpoLvluqYgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOadoeS7tiwKICAgIOWxnuaApywKICAgIOawtOa6liA9IGxldmVsLAogICAg6Kaz5ris5pWwID0gb2JzZXJ2ZWRfbiwKICAgIOe3j+aVsCA9IHRvdGFsX24sCiAgICDoprPmuKzmr5TnjocgPSByb3VuZChvYnNlcnZlZF9zaGFyZSwgNCksCiAgICDmnJ/lvoXmr5TnjocgPSByb3VuZChleHBlY3RlZF9zaGFyZSwgNCksCiAgICDlt64gPSByb3VuZChkZXZpYXRpb24sIDQpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEMxMiksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMgQy40IOaomeacrOa4m+WwkeOBqOOCueOCr+ODquODvOODi+ODs+OCsAoKIyMjIOWun+mokzHvvIgyMDIz5bm077yJCgpgYGB7ciBiNC1zdHVkeTEtc2NyZWVuaW5nLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5a6f6aiTMeaomeacrOa4m+WwkSA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTEiLCAidGFibGVfc2FtcGxlX2F0dHJpdGlvbi5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOautemajiA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCjmrrXpmo4sIGMoImNob2ljZV90YXNrKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIiwgIkNob2ljZSB0YXNrIChbMS01XSkiID0gIumBuOaKnuiqsumhjFxcMSIpKQogICkgJT4lCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzHmqJnmnKzmuJvlsJEsIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzEz77ya5a6f6aiTMeOBruaomeacrOa4m+WwkSIpCgrlrp/pqJMx5p2h5Lu25Yil5qiZ5pysIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MSIsICJ0YWJsZV9zYW1wbGVfYXR0cml0aW9uX2J5X2NvbmRpdGlvbi5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOadoeS7tiA9IOadoeS7tuaXpeacrOiqnijmnaHku7YsICJzdHVkeTEiKSwKICAgIOautemajiA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCjmrrXpmo4sIGMoImNob2ljZV90YXNrKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIiwgIkNob2ljZSB0YXNrIChbMS01XSkiID0gIumBuOaKnuiqsumhjFxcMSIpKQogICkgJT4lCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzHmnaHku7bliKXmqJnmnKwsIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzE077ya5a6f6aiTMeOBruadoeS7tuWIpeaomeacrOa4m+WwkSIpCmBgYAoKCgojIyMg5a6f6aiTMu+8iDIwMjblubTvvIkKCmBgYHtyIGI0LXN0dWR5Mi1zY3JlZW5pbmcsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlrp/pqJMy5qiZ5pys5rib5bCRIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MiIsICJ0YWJsZV9zYW1wbGVfYXR0cml0aW9uLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6bXV0YXRlKOautemajiA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCjmrrXpmo4sIGMoImNob2ljZV90YXNrKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIiwgIkNob2ljZSB0YXNrIChbMS01XSkiID0gIumBuOaKnuiqsumhjFxcMSIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzLmqJnmnKzmuJvlsJEsIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzE377ya5a6f6aiTMuOBruaomeacrOa4m+WwkSIpCgrlrp/pqJMy5p2h5Lu25Yil5qiZ5pysIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MiIsICJ0YWJsZV9zYW1wbGVfYXR0cml0aW9uX2J5X2NvbmRpdGlvbi5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkyIiksIOautemajiA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCjmrrXpmo4sIGMoImNob2ljZV90YXNrKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIiwgIkNob2ljZSB0YXNrIChbMS01XSkiID0gIumBuOaKnuiqsumhjFxcMSIpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzLmnaHku7bliKXmqJnmnKwsIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzE477ya5a6f6aiTMuOBruadoeS7tuWIpeaomeacrOa4m+WwkSIpCgrlrp/pqJMy5pON5L2c56K66KqNIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MiIsICJ0YWJsZV9tYW5pcHVsYXRpb25fY2hlY2suY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjpyZW5hbWVfd2l0aCh+IGRwbHlyOjpyZWNvZGUoLngsIHBhcnR5X24gPSAi5p2h5Lu2IiwgcmVzcG9uc2UgPSAi5Zue562UIiwgc3RhdHVzID0gIuWIpOWumiIsIG4gPSAiTiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKOadoeS7tiA9IOadoeS7tuaXpeacrOiqnijmnaHku7YsICJzdHVkeTIiKSwgZHBseXI6OmFjcm9zcyhkcGx5cjo6ZXZlcnl0aGluZygpLCB+IHRpZHlyOjpyZXBsYWNlX25hKGFzLmNoYXJhY3RlcigueCksICLigJQiKSkpCmtuaXRyOjprYWJsZSjlrp/pqJMy5pON5L2c56K66KqNLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEMxOe+8muWun+mokzLjga7pgbjmip7ogqLmlbDmk43kvZznorroqo0iKQoK5a6f6aiTMuaMh+ekuumgheebriA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTIiLCAidGFibGVfYXR0ZW50aW9uX2NoZWNrLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCByZXNwb25zZSA9ICLlm57nrZTjgrPjg7zjg4kiLCBzdGF0dXMgPSAi5Yik5a6aIiwgbiA9ICJOIikpICU+JQogIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyhkcGx5cjo6ZXZlcnl0aGluZygpLCB+IHRpZHlyOjpyZXBsYWNlX25hKGFzLmNoYXJhY3RlcigueCksICLigJQiKSkpCmtuaXRyOjprYWJsZSjlrp/pqJMy5oyH56S66aCF55uuLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEMyMO+8muWun+mokzLjga7mjIfnpLrpoIXnm64iKQpgYGAKCiMjIyDlrp/pqJMz77yIMjAyNuW5tO+8iQoKYGBge3IgYjQtc3R1ZHkzLXNjcmVlbmluZywgZWNobz1UUlVFLCBldmFsPVRSVUV9CuWun+mokzPmqJnmnKzmuJvlsJEgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX3NhbXBsZV9hdHRyaXRpb24uY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjptdXRhdGUo5q616ZqOID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKOautemajiwgYygiY2hvaWNlX3Rhc2soWzEtNV0pIiA9ICLpgbjmip7oqrLpoYxcXDEiLCAiQ2hvaWNlIHRhc2sgKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIikpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoZHBseXI6OmV2ZXJ5dGhpbmcoKSwgfiB0aWR5cjo6cmVwbGFjZV9uYShhcy5jaGFyYWN0ZXIoLngpLCAi4oCUIikpKQprbml0cjo6a2FibGUo5a6f6aiTM+aomeacrOa4m+WwkSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahDMjHvvJrlrp/pqJMz44Gu5qiZ5pys5rib5bCRIikKCuWun+mokzPmnaHku7bliKXmqJnmnKwgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX3NhbXBsZV9hdHRyaXRpb25fYnlfY29uZGl0aW9uLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6bXV0YXRlKOadoeS7tiA9IOadoeS7tuaXpeacrOiqnijmnaHku7YsICJzdHVkeTMiKSwg5q616ZqOID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKOautemajiwgYygiY2hvaWNlX3Rhc2soWzEtNV0pIiA9ICLpgbjmip7oqrLpoYxcXDEiLCAiQ2hvaWNlIHRhc2sgKFsxLTVdKSIgPSAi6YG45oqe6Kqy6aGMXFwxIikpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoZHBseXI6OmV2ZXJ5dGhpbmcoKSwgfiB0aWR5cjo6cmVwbGFjZV9uYShhcy5jaGFyYWN0ZXIoLngpLCAi4oCUIikpKQprbml0cjo6a2FibGUo5a6f6aiTM+adoeS7tuWIpeaomeacrCwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahDMjLvvJrlrp/pqJMz44Gu5p2h5Lu25Yil5qiZ5pys5rib5bCRIikKCuWun+mokzPmk43kvZznorroqo0gPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX21hbmlwdWxhdGlvbl9jaGVjay5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCByZXNwb25zZSA9ICLlm57nrZQiLCBzdGF0dXMgPSAi5Yik5a6aIiwgbiA9ICJOIikpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tiwgInN0dWR5MyIpLCBkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzPmk43kvZznorroqo0sIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzIz77ya5a6f6aiTM+OBrumBuOaKnuiCouaVsOaTjeS9nOeiuuiqjSIpCgrlrp/pqJMz5oyH56S66aCF55uuIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9hdHRlbnRpb25fY2hlY2suY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjpyZW5hbWVfd2l0aCh+IGRwbHlyOjpyZWNvZGUoLngsIHJlc3BvbnNlID0gIuWbnuetlOOCs+ODvOODiSIsIHN0YXR1cyA9ICLliKTlrpoiLCBuID0gIk4iKSkgJT4lCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRwbHlyOjpldmVyeXRoaW5nKCksIH4gdGlkeXI6OnJlcGxhY2VfbmEoYXMuY2hhcmFjdGVyKC54KSwgIuKAlCIpKSkKa25pdHI6OmthYmxlKOWun+mokzPmjIfnpLrpoIXnm64sIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoQzI077ya5a6f6aiTM+OBruaMh+ekuumgheebriIpCmBgYAoKIyBELiDmnKzmloflm7Pjga7lho3nj74KCuOBk+OBruevgOOBruWbs++8iOihqO+8ieeVquWPt+OBr+acrOaWh+OBqOS4gOiHtOOBl+OBn+OCguOBruOBp+OBguOCi+OAguacrOaWh+OBruWIhuaekOe1kOaenOOBp+eUqOOBhOOCi+Wbs+OBr+WbszTjgYvjgonlm7M544G+44Gn44Gn44GC44KK44CB5a6f6aiTMuOBrkFNQ0Xjga/mnKzmloflm7Pjgavjga/ooajnpLrjgZvjgZrjgIHoo5zpgbpF44Gr5o6y56S644GV44KM44Gm44GE44KL44CCCgojIyDlm7M077ya5a6f6aiTMe+8iDIwMjPlubTvvInjga7lhbHlpInph4/oqr/mlbTmuIjjgb9BTUNFCgpgYGB7ciBjLWZpZzQsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlm7M044OH44O844K/IDwtIHN0dWR5MV9lbnYkYW1jZV9wbG90X2RmX2Nvdl9mYWNldArlm7M0IDwtIGdncGxvdDI6OmdncGxvdCgKICDlm7M044OH44O844K/LAogIGdncGxvdDI6OmFlcyh4ID0gZXN0aW1hdGVfcHAsIHkgPSBsYWJlbCwgc2hhcGUgPSBwYXJ0eV9uLCBsaW5ldHlwZSA9IHBhcnR5X24sIGdyb3VwID0gcGFydHlfbikKKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC40NSwgY29sb3IgPSAiZ3JleTM1IikgKwogIGdncGxvdDI6Omdlb21fZXJyb3JiYXJoKAogICAgZ2dwbG90Mjo6YWVzKHhtaW4gPSBjb25mLmxvd19wcCwgeG1heCA9IGNvbmYuaGlnaF9wcCksCiAgICBwb3NpdGlvbiA9IGdncGxvdDI6OnBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksIGhlaWdodCA9IDAuMTYsIGxpbmV3aWR0aCA9IDAuNTUKICApICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHBvc2l0aW9uID0gZ2dwbG90Mjo6cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwgc2l6ZSA9IDIuNSwgZmlsbCA9ICJ3aGl0ZSIsIHN0cm9rZSA9IDAuOCkgKwogIGdncGxvdDI6OmZhY2V0X2dyaWQoYXR0cmlidXRlX2ZhY2V0IH4gLiwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIsIHN3aXRjaCA9ICJ5IikgKwogIGdncGxvdDI6OnNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCIy5pS/5YWaIiA9IDE2LCAiM+aUv+WFmiIgPSAxNywgIjTmlL/lhZoiID0gMTUsICI15pS/5YWaIiA9IDEpKSArCiAgZ2dwbG90Mjo6c2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoIjLmlL/lhZoiID0gInNvbGlkIiwgIjPmlL/lhZoiID0gImRhc2hlZCIsICI05pS/5YWaIiA9ICJkb3R0ZWQiLCAiNeaUv+WFmiIgPSAiZG90ZGFzaCIpKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIumBuOaKnueiuueOh+OBruWkieWMliIsIHkgPSBOVUxMLCBzaGFwZSA9ICLmlL/lhZrmlbDmnaHku7YiLCBsaW5ldHlwZSA9ICLmlL/lhZrmlbDmnaHku7YiKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpICsKICBnZ3Bsb3QyOjp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5tYWpvci55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpKQrlm7M0CgrooahEMSA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTEiLCAidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0gcGFzdGUwKHN0cmluZ3I6OnN0cl9yZW1vdmUo5p2h5Lu2LCAi5p2h5Lu2JCIpLCAi5p2h5Lu2IikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRDEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEQx77ya5ZuzNOOBq+WvvuW/nOOBmeOCi+WFseWkiemHj+iqv+aVtOa4iOOBv0FNQ0UiKQpgYGAKCiMjIOWbszXvvJrlrp/pqJMx77yIMjAyM+W5tO+8ieOBruaUv+WFmuODu+e1jOa4iOaJi+OBjOOBi+OCiuOBrumHjeimgeW6puOBqOebuOWvvuavlOmHjQoKYGBge3IgYy1maWc1LCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5ZuzNemHjeimgeW6puODh+ODvOOCvyA8LSBzdHVkeTFfZW52JHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkX2RhdGEK5ZuzNeebuOWvvuavlOmHjeODh+ODvOOCvyA8LSBzdHVkeTFfZW52JHJlbGF0aXZlX3BhbmVsX2JfZGF0YQrlm7M144OR44ON44OrQSA8LSBzdHVkeTFfZW52JHJlbGF0aXZlX3BhbmVsX2FkanVzdGVkCuWbszXjg5Hjg43jg6tCIDwtIHN0dWR5MV9lbnYkcmVsYXRpdmVfcGFuZWxfYwrlm7M1IDwtICjlm7M144OR44ON44OrQSB8IOWbszXjg5Hjg43jg6tCKSArIHBhdGNod29yazo6cGxvdF9sYXlvdXQod2lkdGhzID0gYygxLCAxKSkK5ZuzNQoK6KGoRDIgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkxIiwgInRhYmxlX21hcmdpbmFsX21lYW5zLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBwYXJ0eV9uID0gIuadoeS7tiIsIGF0dHJpYnV0ZSA9ICLlsZ7mgKciLCBsZXZlbCA9ICLmsLTmupYiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkxIiksIOWxnuaApyA9IOWxnuaAp+aXpeacrOiqnijlsZ7mgKcpKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEQyKSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahEMu+8mumZkOeVjOW5s+WdhyIpCgrooahEMyA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTEiLCAidGFibGVfYXR0cmlidXRlX2ltcG9ydGFuY2UuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjpyZW5hbWVfd2l0aCh+IGRwbHlyOjpyZWNvZGUoLngsIHBhcnR5X24gPSAi5p2h5Lu2IiwgYXR0cmlidXRlID0gIuWxnuaApyIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKOadoeS7tiA9IOadoeS7tuaXpeacrOiqnijmnaHku7YsICJzdHVkeTEiKSwg5bGe5oCnID0g5bGe5oCn5pel5pys6KqeKOWxnuaApykpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRDMpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEQz77ya5bGe5oCn6YeN6KaB5bqmIikKCuihqEQ0IDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MSIsICJ0YWJsZV9jdWVfaW1wb3J0YW5jZS5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCBzdGF0aXN0aWMgPSAi5oyH5qiZIikpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tiwgInN0dWR5MSIpLCDmjIfmqJkgPSDntbHoqIjph4/ml6XmnKzoqp4o5oyH5qiZLCAic3R1ZHkxIikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRDQpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEQ077ya5pS/5YWa44O757WM5riI5omL44GM44GL44KK44Gu6YeN6KaB5bqm44Go55u45a++5q+U6YeNIikKYGBgCgojIyDlm7M277ya5a6f6aiTMu+8iDIwMjblubTvvInjga7mlL/lhZrjg7vntYzmuIjmiYvjgYzjgYvjgorjga7ph43opoHluqbjgajnm7jlr77mr5Tph40KCmBgYHtyIGMtZmlnNiwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuWbszbph43opoHluqbjg4fjg7zjgr8gPC0gc3R1ZHkyX2VudiRyZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZF9kYXRhCuWbszbnm7jlr77mr5Tph43jg4fjg7zjgr8gPC0gc3R1ZHkyX2VudiRyZWxhdGl2ZV9wYW5lbF9iX2RhdGEK5ZuzNuODkeODjeODq0EgPC0gc3R1ZHkyX2VudiRyZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZArlm7M244OR44ON44OrQiA8LSBzdHVkeTJfZW52JHJlbGF0aXZlX3BhbmVsX2MK5ZuzNiA8LSAo5ZuzNuODkeODjeODq0EgfCDlm7M244OR44ON44OrQikgKyBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMSwgMSkpCuWbszYKCuihqEQ1IDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MiIsICJ0YWJsZV9tYXJnaW5hbF9tZWFucy5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCBhdHRyaWJ1dGUgPSAi5bGe5oCnIiwgbGV2ZWwgPSAi5rC05rqWIikpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tiwgInN0dWR5MiIpLCDlsZ7mgKcgPSDlsZ7mgKfml6XmnKzoqp4o5bGe5oCnKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahENSksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoRDXvvJrpmZDnlYzlubPlnYciKQoK6KGoRDYgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkyIiwgInRhYmxlX2F0dHJpYnV0ZV9pbXBvcnRhbmNlLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBwYXJ0eV9uID0gIuadoeS7tiIsIGF0dHJpYnV0ZSA9ICLlsZ7mgKciKSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkyIiksIOWxnuaApyA9IOWxnuaAp+aXpeacrOiqnijlsZ7mgKcpKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEQ2KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahENu+8muWxnuaAp+mHjeimgeW6piIpCgrooahENyA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTIiLCAidGFibGVfY3VlX2ltcG9ydGFuY2UuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjpyZW5hbWVfd2l0aCh+IGRwbHlyOjpyZWNvZGUoLngsIHBhcnR5X24gPSAi5p2h5Lu2Iiwgc3RhdGlzdGljID0gIuaMh+aomSIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKOadoeS7tiA9IOadoeS7tuaXpeacrOiqnijmnaHku7YsICJzdHVkeTIiKSwg5oyH5qiZID0g57Wx6KiI6YeP5pel5pys6KqeKOaMh+aomSwgInN0dWR5MiIpKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEQ3KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahEN++8muaUv+WFmuODu+e1jOa4iOaJi+OBjOOBi+OCiuOBrumHjeimgeW6puOBqOebuOWvvuavlOmHjSIpCmBgYAoKIyMg5ZuzN++8muWun+mokzPvvIgyMDI25bm077yJ44Gu5YWx5aSJ6YeP6Kq/5pW05riI44G/QU1DRQoKYGBge3IgYy1maWc3LCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5ZuzN+ODh+ODvOOCvyA8LSBzdHVkeTNfZW52JGFtY2VfcGxvdF9jb3YK5ZuzNyA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAg5ZuzN+ODh+ODvOOCvywKICBnZ3Bsb3QyOjphZXMoeCA9IGVzdGltYXRlX3BwLCB5ID0gbGFiZWwsIHNoYXBlID0gcGFydHlfbiwgbGluZXR5cGUgPSBwYXJ0eV9uLCBncm91cCA9IHBhcnR5X24pCikgKwogIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV3aWR0aCA9IDAuNDUsIGNvbG9yID0gImdyZXkzNSIpICsKICBnZ3Bsb3QyOjpnZW9tX2Vycm9yYmFyaCgKICAgIGdncGxvdDI6OmFlcyh4bWluID0gY29uZi5sb3dfcHAsIHhtYXggPSBjb25mLmhpZ2hfcHApLAogICAgcG9zaXRpb24gPSBnZ3Bsb3QyOjpwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLCBoZWlnaHQgPSAwLjE2LCBsaW5ld2lkdGggPSAwLjU1CiAgKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChwb3NpdGlvbiA9IGdncGxvdDI6OnBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksIHNpemUgPSAyLjUsIGZpbGwgPSAid2hpdGUiLCBzdHJva2UgPSAwLjgpICsKICBnZ3Bsb3QyOjpmYWNldF9ncmlkKGF0dHJpYnV0ZSB+IC4sIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiLCBzd2l0Y2ggPSAieSIpICsKICBnZ3Bsb3QyOjpzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiMumBuOaKnuiCoiIgPSAxNiwgIjPpgbjmip7ogqIiID0gMTcsICI06YG45oqe6IKiIiA9IDE1LCAiNemBuOaKnuiCoiIgPSAxKSkgKwogIGdncGxvdDI6OnNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCIy6YG45oqe6IKiIiA9ICJzb2xpZCIsICIz6YG45oqe6IKiIiA9ICJkYXNoZWQiLCAiNOmBuOaKnuiCoiIgPSAiZG90dGVkIiwgIjXpgbjmip7ogqIiID0gImRvdGRhc2giKSkgKwogIGdncGxvdDI6OmxhYnMoeCA9ICLpgbjmip7norrnjofjga7lpInljJYiLCB5ID0gTlVMTCwgc2hhcGUgPSAi6YG45oqe6IKi5pWwIiwgbGluZXR5cGUgPSAi6YG45oqe6IKi5pWwIikgKwogIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHBhbmVsLmdyaWQubWFqb3IueSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSkK5ZuzNwoK6KGoRDggPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX2FtY2VfY292YXJpYXRlX2FkanVzdGVkLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6bXV0YXRlKOadoeS7tiA9IHBhc3RlMChzdHJpbmdyOjpzdHJfcmVtb3ZlKOadoeS7tiwgIuadoeS7tiQiKSwgIuadoeS7tiIpKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEQ4KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICLooahEOO+8muWbszfjgavlr77lv5zjgZnjgovlhbHlpInph4/oqr/mlbTmuIjjgb9BTUNFIikKYGBgCgojIyDlm7M477ya5a6f6aiTM++8iDIwMjblubTvvInjga7mlL/lhZrlkI3jg7vntYzmuIjmiYvjgYzjgYvjgorjga7ph43opoHluqbjgajnm7jlr77mr5Tph40KCmBgYHtyIGMtZmlnOCwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuWbszjph43opoHluqbjg4fjg7zjgr8gPC0gc3R1ZHkzX2VudiRyZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZF9kYXRhCuWbszjnm7jlr77mr5Tph43jg4fjg7zjgr8gPC0gc3R1ZHkzX2VudiRyZWxhdGl2ZV9wYW5lbF9iX2RhdGEK5ZuzOOODkeODjeODq0EgPC0gc3R1ZHkzX2VudiRyZWxhdGl2ZV9wYW5lbF9hZGp1c3RlZArlm7M444OR44ON44OrQiA8LSBzdHVkeTNfZW52JHJlbGF0aXZlX3BhbmVsX2MK5ZuzOCA8LSAo5ZuzOOODkeODjeODq0EgfCDlm7M444OR44ON44OrQikgKyBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMSwgMSkpCuWbszgKCuihqEQ5IDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9tYXJnaW5hbF9tZWFucy5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCBhdHRyaWJ1dGUgPSAi5bGe5oCnIiwgbGV2ZWwgPSAi5rC05rqWIikpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tiwgInN0dWR5MyIpLCDlsZ7mgKcgPSDlsZ7mgKfml6XmnKzoqp4o5bGe5oCnKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahEOSksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAi6KGoRDnvvJrpmZDnlYzlubPlnYciKQoK6KGoRDEwIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9hdHRyaWJ1dGVfaW1wb3J0YW5jZS5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCBhdHRyaWJ1dGUgPSAi5bGe5oCnIikpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tiwgInN0dWR5MyIpLCDlsZ7mgKcgPSDlsZ7mgKfml6XmnKzoqp4o5bGe5oCnKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahEMTApLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEQxMO+8muWxnuaAp+mHjeimgeW6piIpCgrooahEMTEgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX2N1ZV9pbXBvcnRhbmNlLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBwYXJ0eV9uID0gIuadoeS7tiIsIHN0YXRpc3RpYyA9ICLmjIfmqJkiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkzIiksIOaMh+aomSA9IOe1seioiOmHj+aXpeacrOiqnijmjIfmqJksICJzdHVkeTMiKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahEMTEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEQxMe+8muaUv+WFmuWQjeODu+e1jOa4iOaJi+OBjOOBi+OCiuOBrumHjeimgeW6puOBqOebuOWvvuavlOmHjSIpCmBgYAoKIyMg5ZuzOe+8muWun+mokzPvvIgyMDI25bm077yJ44Gu5pSv5oyB5pS/5YWa44Go5o+Q56S65pS/5YWa5ZCN44Gu5LiA6Ie05Yq55p6cCgpgYGB7ciBjLWZpZzksIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrlm7M5IDwtIHN0dWR5M19lbnYkcF9wYXJ0eV9tYXRjaArlm7M5CgrooahEMTLlhYMgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX3BhcnR5X21hdGNoLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoK6KGoRDEy5p2h5Lu25YiXIDwtIGludGVyc2VjdChjKCLpgbjmip7ogqLmlbAiLCAi5p2h5Lu2IiwgInBhcnR5X24iKSwgbmFtZXMo6KGoRDEy5YWDKSkKaWYgKGxlbmd0aCjooahEMTLmnaHku7bliJcpID09IDApIHN0b3AoIkNoZWNrIGNvbmRpdGlvbiBjb2x1bW4iKQrooahEMTLmnaHku7bliJcgPC0g6KGoRDEy5p2h5Lu25YiXW1sxXV0KCmlmICghIuWbnuetlOiAheaVsCIgJWluJSBuYW1lcyjooahEMTLlhYMpKSB7CiAg6KGoRDEy5YWDJOWbnuetlOiAheaVsCA8LSBOQV9jaGFyYWN0ZXJfCn0KCuWun+mokzPmnaHku7bkurrmlbAgPC0gc3R1ZHkzX2VudiRjb25qb2ludF9hbGxfbSAlPiUKICBkcGx5cjo6ZGlzdGluY3QoSUQsIHBhcnR5X24pICU+JQogIGRwbHlyOjpjb3VudChwYXJ0eV9uLCBuYW1lID0gIuWbnuetlOiAheaVsOijnOWujCIpCgrooahEMTIgPC0g6KGoRDEy5YWDICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu25pWwID0g5pWw5YCk5YiXKC5kYXRhW1vooahEMTLmnaHku7bliJddXSkpICU+JQogIGRwbHlyOjpzZWxlY3QoLWRwbHlyOjphbGxfb2Yo6KGoRDEy5p2h5Lu25YiXKSkgJT4lCiAgZHBseXI6OmxlZnRfam9pbijlrp/pqJMz5p2h5Lu25Lq65pWwLCBieSA9IGMoIuadoeS7tuaVsCIgPSAicGFydHlfbiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAg5Zue562U6ICF5pWwID0gZHBseXI6OmNvYWxlc2NlKOaVsOWApOWIlyjlm57nrZTogIXmlbApLCDlm57nrZTogIXmlbDoo5zlrowpLAogICAg5p2h5Lu2ID0g5p2h5Lu25pel5pys6KqeKOadoeS7tuaVsCwgInN0dWR5MyIpCiAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KC3mnaHku7bmlbAsIC3lm57nrZTogIXmlbDoo5zlrowpICU+JQogIGRwbHlyOjpyZWxvY2F0ZSjmnaHku7YsIC5hZnRlciA9IOWvvuixoSkKCmtuaXRyOjprYWJsZSgKICDooajml6XmnKzoqp4o6KGoRDEyKSwKICBmb3JtYXQgPSAiaHRtbCIsCiAgcm93Lm5hbWVzID0gRkFMU0UsCiAgY2FwdGlvbiA9ICLooahEMTLvvJrmlK/mjIHmlL/lhZrjgajmj5DnpLrmlL/lhZrlkI3jga7kuIDoh7TlirnmnpwiCikKYGBgCgojIEUuIOWun+mokzHvvIgyMDIz5bm077yJ44Gu6KOc6Laz5YiG5p6QCgojIyDoo5zlm7NFMe+8muWFseWkiemHj+OCkuWQq+OCgeOBquOBhEFNQ0UKCmBgYHtyIGQxLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KOc5ZuzRTHjg4fjg7zjgr8gPC0gc3R1ZHkxX2VudiRhbWNlX3Bsb3RfZGZfbm9jb3ZfZmFjZXQK6KOc5ZuzRTEgPC0gc3R1ZHkxX2VudiRwX2FtY2VfZmFjZXRfbm9jb3YK6KOc5ZuzRTEKCuihqEUxIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MSIsICJ0YWJsZV9hbWNlX3VuYWRqdXN0ZWQuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0gcGFzdGUwKHN0cmluZ3I6OnN0cl9yZW1vdmUo5p2h5Lu2LCAi5p2h5Lu2JCIpLCAi5p2h5Lu2IikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRTEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOijnOWbs0Uy77yaMuaUv+WFmuadoeS7tuOBqOOBruW3rgoKYGBge3IgZDIsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQroo5zlm7NFMuODh+ODvOOCvyA8LSBzdHVkeTFfZW52JGludGVyYWN0aW9uX3Bsb3RfZGYK6KOc5ZuzRTIgPC0gc3R1ZHkxX2VudiRwX2ludGVyYWN0aW9uCuijnOWbs0UyCgrooahFMiA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTEiLCAidGFibGVfYW1jZV9pbnRlcmFjdGlvbi5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgYXR0cmlidXRlID0gIuWxnuaApyIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoZHBseXI6OmFueV9vZigi5bGe5oCnIiksIOWxnuaAp+aXpeacrOiqnikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRTIpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOijnOWbs0Uz77ya5p2h5Lu25LuY44GN44Ot44K444OD44OICgpgYGB7ciBkMywgZWNobz1UUlVFLCBldmFsPVRSVUV9CuijnOWbs0UzIDwtIHN0dWR5MV9lbnYkcF9jbG9naXRfb3IK6KOc5ZuzRTMKCuihqEUzIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MSIsICJ0YWJsZV9jb25kaXRpb25hbF9sb2dpdC5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgcGFydHlfbiA9ICLmnaHku7YiLCBhdHRyaWJ1dGUgPSAi5bGe5oCnIiwgbGFiZWwgPSAi5rC05rqWIikpICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkxIiksCiAgICDlsZ7mgKcgPSDlsZ7mgKfml6XmnKzoqp4o5bGe5oCnKQogICkgJT4lCiAgZHBseXI6OnNlbGVjdCgtZHBseXI6OmFueV9vZihjKCJ0ZXJtIiwgInZhcmlhYmxlIiwgInBvbGljeV9wb3NpdGlvbiIsICJnb3Zlcm5tZW50X3N0YXR1cyIpKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahFMyksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyBGLiDlrp/pqJMy77yIMjAyNuW5tO+8ieOBruijnOi2s+WIhuaekAoK5pys5paH44Gn44Gv5a6f6aiTMuOBrkFNQ0Xjga7mlrnlkJHmgKfjgpLoqJjov7DjgZfjgIHoqbPntLDjgpLoo5zpgbrjgavlm57jgZfjgabjgYTjgovjgZ/jgoHjgIHlhbHlpInph4/oqr/mlbTmuIjjgb9BTUNF44KS6KOc5ZuzRjHjgajjgZfjgabmnIDliJ3jgavnpLrjgZnjgIIKCiMjIOijnOWbs0Yx77ya5YWx5aSJ6YeP6Kq/5pW05riI44G/QU1DRQoKYGBge3IgZTEsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQroo5zlm7NGMeODh+ODvOOCvyA8LSBzdHVkeTJfZW52JGFtY2VfcGxvdF9kZl9jb3ZfZmFjZXQK6KOc5ZuzRjEgPC0gc3R1ZHkyX2VudiRwX2FtY2VfY292X2ZhY2V0CuijnOWbs0YxCgrooahGMSA8LSByZWFkcjo6cmVhZF9jc3Yoc3R1ZHlfY3N2KCJzdHVkeTIiLCAidGFibGVfYW1jZV9jb3ZhcmlhdGVfYWRqdXN0ZWQuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0gcGFzdGUwKHN0cmluZ3I6OnN0cl9yZW1vdmUo5p2h5Lu2LCAi5p2h5Lu2JCIpLCAi5p2h5Lu2IikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRjEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOijnOWbs0Yy77ya5YWx5aSJ6YeP44KS5ZCr44KB44Gq44GEQU1DRQoKYGBge3IgZTIsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQroo5zlm7NGMuODh+ODvOOCvyA8LSBzdHVkeTJfZW52JGFtY2VfcGxvdF9kZl9ub2Nvdl9mYWNldAroo5zlm7NGMiA8LSBzdHVkeTJfZW52JHBfYW1jZV9mYWNldF9ub2Nvdgroo5zlm7NGMgoK6KGoRjIgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkyIiwgInRhYmxlX2FtY2VfdW5hZGp1c3RlZC5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSBwYXN0ZTAoc3RyaW5ncjo6c3RyX3JlbW92ZSjmnaHku7YsICLmnaHku7YkIiksICLmnaHku7YiKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahGMiksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg6KOc5ZuzRjPvvJoy5pS/5YWa5p2h5Lu244Go44Gu5beuCgpgYGB7ciBlMywgZWNobz1UUlVFLCBldmFsPVRSVUV9CuijnOWbs0Yz44OH44O844K/IDwtIHN0dWR5Ml9lbnYkaW50ZXJhY3Rpb25fcGxvdF9kZgroo5zlm7NGMyA8LSBzdHVkeTJfZW52JHBfaW50ZXJhY3Rpb24K6KOc5ZuzRjMKCuihqEYzIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MiIsICJ0YWJsZV9hbWNlX2ludGVyYWN0aW9uLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBhdHRyaWJ1dGUgPSAi5bGe5oCnIikpICU+JQogIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyhkcGx5cjo6YW55X29mKCLlsZ7mgKciKSwg5bGe5oCn5pel5pys6KqeKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahGMyksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg6KOc5ZuzRjTvvJrmnaHku7bku5jjgY3jg63jgrjjg4Pjg4gKCmBgYHtyIGU0LCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KOc5ZuzRjQgPC0gc3R1ZHkyX2VudiRwX2Nsb2dpdF9vcgroo5zlm7NGNAoK6KGoRjQgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkyIiwgInRhYmxlX2NvbmRpdGlvbmFsX2xvZ2l0LmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBwYXJ0eV9uID0gIuadoeS7tiIsIGF0dHJpYnV0ZSA9ICLlsZ7mgKciLCBsYWJlbCA9ICLmsLTmupYiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkyIiksIOWxnuaApyA9IOWxnuaAp+aXpeacrOiqnijlsZ7mgKcpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1kcGx5cjo6YW55X29mKGMoInRlcm0iLCAidmFyaWFibGUiLCAicG9saWN5X3Bvc2l0aW9uIiwgImdvdmVybm1lbnRfc3RhdHVzIikpKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEY0KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIEcuIOWun+mokzPvvIgyMDI25bm077yJ44Gu6KOc6Laz5YiG5p6QCgojIyDoo5zlm7NHMe+8muWFseWkiemHj+OCkuWQq+OCgeOBquOBhEFNQ0UKCmBgYHtyIGYxLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KOc5ZuzRzHjg4fjg7zjgr8gPC0gc3R1ZHkzX2VudiRhbWNlX3Bsb3Rfbm9jb3YK6KOc5ZuzRzEgPC0gc3R1ZHkzX2VudiRwX2FtY2Vfbm9jb3YK6KOc5ZuzRzEKCuihqEcxIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9hbWNlX3VuYWRqdXN0ZWQuY3N2IiksIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGRwbHlyOjptdXRhdGUo5p2h5Lu2ID0gcGFzdGUwKHN0cmluZ3I6OnN0cl9yZW1vdmUo5p2h5Lu2LCAi5p2h5Lu2JCIpLCAi5p2h5Lu2IikpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRzEpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIOijnOWbs0cy77yaMumBuOaKnuiCouadoeS7tuOBqOOBruW3rgoKYGBge3IgZjIsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQroo5zlm7NHMiA8LSBzdHVkeTNfZW52JHBfaW50ZXJhY3Rpb24K6KOc5ZuzRzIKCuihqEcyIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9hbWNlX2ludGVyYWN0aW9uLmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBhdHRyaWJ1dGUgPSAi5bGe5oCnIikpICU+JQogIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyhkcGx5cjo6YW55X29mKCLlsZ7mgKciKSwg5bGe5oCn5pel5pys6KqeKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahHMiksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg6KOc5ZuzRzPvvJpBTUNF44Gu57ea5b2i44OI44Os44Oz44OJCgpgYGB7ciBmMywgZWNobz1UUlVFLCBldmFsPVRSVUV9CuijnOWbs0czIDwtIHN0dWR5M19lbnYkcF9saW5lYXJfdHJlbmQK6KOc5ZuzRzMKCuihqEczIDwtIHJlYWRyOjpyZWFkX2NzdihzdHVkeV9jc3YoInN0dWR5MyIsICJ0YWJsZV9hbWNlX2xpbmVhcl90cmVuZC5jc3YiKSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnJlbmFtZV93aXRoKH4gZHBseXI6OnJlY29kZSgueCwgYXR0cmlidXRlID0gIuWxnuaApyIsIGxhYmVsID0gIuawtOa6liIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoZHBseXI6OmFueV9vZigi5bGe5oCnIiksIOWxnuaAp+aXpeacrOiqnikpICU+JQogIGRwbHlyOjpzZWxlY3QoLWRwbHlyOjphbnlfb2YoYygidGVybSIsICJ2YXJpYWJsZSIpKSkKa25pdHI6OmthYmxlKOihqOaXpeacrOiqnijooahHMyksIGZvcm1hdCA9ICJodG1sIiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMg6KOc5ZuzRzTvvJrmnaHku7bku5jjgY3jg63jgrjjg4Pjg4gKCmBgYHtyIGY0LCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KOc5ZuzRzQgPC0gc3R1ZHkzX2VudiRwX2Nsb2dpdF9vcgroo5zlm7NHNAoK6KGoRzQgPC0gcmVhZHI6OnJlYWRfY3N2KHN0dWR5X2Nzdigic3R1ZHkzIiwgInRhYmxlX2NvbmRpdGlvbmFsX2xvZ2l0LmNzdiIpLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBkcGx5cjo6cmVuYW1lX3dpdGgofiBkcGx5cjo6cmVjb2RlKC54LCBwYXJ0eV9uID0gIuadoeS7tiIsIGF0dHJpYnV0ZSA9ICLlsZ7mgKciLCBsYWJlbCA9ICLmsLTmupYiKSkgJT4lCiAgZHBseXI6Om11dGF0ZSjmnaHku7YgPSDmnaHku7bml6XmnKzoqp4o5p2h5Lu2LCAic3R1ZHkzIiksIOWxnuaApyA9IOWxnuaAp+aXpeacrOiqnijlsZ7mgKcpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1kcGx5cjo6YW55X29mKGMoInRlcm0iLCAidmFyaWFibGUiKSkpCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoRzQpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgSC4g5pS/5YWa5pSv5oyB44Gr44KI44KL55Ww6LOq5oCnCgrmlK/mjIHmlL/lhZrliKVBTUNF44Gn44Gv44CB5ZCE5p2h5Lu244Gr6Kmy5b2T44GZ44KL5Zue562U6ICF5pWw44GMNDDkurrmnKrmuoDjga7jgrvjg6vjga/mjqjlrprlr77osaHlpJbjgajjgZfjgabjgYTjgovjgILjgZfjgZ/jgYzjgaPjgabjgIHku6XkuIvjgafjga8gYGluc3VmZmljaWVudF9jZWxsX25gIOOCkk5B44Gu44G+44G+6KGo56S644Gb44Ga44CB5o6o5a6a5Y+v6IO944Gn44GC44Gj44Gf5pSv5oyB5pS/5YWaw5fpgbjmip7ogqLmlbDmnaHku7bjga7jgb/jgpLmjrLovInjgZnjgovjgIIKCiMjIOijnOWbs0gx77ya5pSv5oyB5pS/5YWa5YilQU1DRQoK6KOc5ZuzSDHjga/jgIHmlK/mjIHmlL/lhZrjgavjgojjgotBTUNF44Gu55Ww6LOq5oCn44KS5a6f6aiT44GU44Go44Gr56S644GZ44CC5Y+v6Kqt5oCn44Gu44Gf44KB44CB57WQ5p6c44Gv5a6f6aiTMeODuzLjg7sz44Gr5YiG44GR44CBKiox44Gk44Gu44OR44ON44Or44KSMeOBpOOBruaUr+aMgeaUv+WFmuOBq+WvvuW/nOOBleOBm+OCiyoq44CC57im6Lu444Gr44Gv5bGe5oCn5ZCN44Go5rC05rqW5ZCN44KS5LiA5L2T44Go44GX44Gm6KGo56S644GX44CB5ZCM5LiA44Gu5pSv5oyB5pS/5YWa44Gr44Gk44GE44Gm5ZCE5bGe5oCn44O75rC05rqW44Gu5o6o5a6a57WQ5p6c44KS5LiK44GL44KJ6aCG44Gr56K66KqN44Gn44GN44KL44KI44GG44Gr44GX44Gf44CC54K544GvQU1DReOAgeaoque3muOBrzk1JeS/oemgvOWMuumWk+OCkuekuuOBl+OAgeeCueOBruW9ouOBp+mBuOaKnuiCouaVsOadoeS7tuOCkuWMuuWIpeOBmeOCi+OAggoK5a++5b+c6KGo44KC5a6f6aiT44GU44Go44Gr5YiG44GR44CB6YG45oqe6IKi5pWw5p2h5Lu244KS5YiX5pa55ZCR44Gr5bGV6ZaL44GZ44KL44CC5ZCE44K744Or44GvICoqQU1DRSBbOTUlIENJXe+8iHBw77yJKiog44KS56S644GX44CB5Zue562U6ICF5pWw44Gv5pSv5oyB5pS/5YWaw5fpgbjmip7ogqLmlbDmnaHku7bjgZTjgajjga7lsI/ooajjgajjgZfjgabliKXjgavnpLrjgZnjgILjgZPjga7lvaLlvI/jgavjgojjgorjgIHlkIzjgZjlsZ7mgKfjg7vmsLTmupbjgavjgaTjgYTjgaYy44O7M+ODuzTjg7s16YG45oqe6IKi5p2h5Lu244KS5qiq5pa55ZCR44Gr55u05o6l5q+U6LyD44Gn44GN44KL44CC6KGo56S66KGo44Gn44Gv5oOF5aCx44KS54K55o6o5a6a5YCk44GoOTUl5L+h6aC85Yy66ZaT44Gr6ZuG57SE44GX44CBcOWApOOCkuWQq+OCgOWujOWFqOOBquS/guaVsOihqOOBr+WQhOWun+mok+OBrkNTVuWHuuWKmyBgdGFibGVfcGFydHlfc3VwcG9ydF9hbWNlLmNzdmAg44Gr5L+d5a2Y44GZ44KL44CCCgpgYGB7ciBnMS1wcmVwYXJlLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5pSv5oyBQU1DReS4gOimpyA8LSBkcGx5cjo6YmluZF9yb3dzKAogIHBhcnR5X3N1cHBvcnRfYW1jZV9yZXN1bHRzJHN0dWR5MSRzdWJncm91cF9jb2VmZmljaWVudHMgJT4lCiAgICBkcGx5cjo6bXV0YXRlKOWun+mokyA9ICLlrp/pqJMx77yIMjAyM+W5tO+8iSIsIHN0dWR5X2lkID0gInN0dWR5MSIpLAogIHBhcnR5X3N1cHBvcnRfYW1jZV9yZXN1bHRzJHN0dWR5MiRzdWJncm91cF9jb2VmZmljaWVudHMgJT4lCiAgICBkcGx5cjo6bXV0YXRlKOWun+mokyA9ICLlrp/pqJMy77yIMjAyNuW5tO+8iSIsIHN0dWR5X2lkID0gInN0dWR5MiIpLAogIHBhcnR5X3N1cHBvcnRfYW1jZV9yZXN1bHRzJHN0dWR5MyRzdWJncm91cF9jb2VmZmljaWVudHMgJT4lCiAgICBkcGx5cjo6bXV0YXRlKOWun+mokyA9ICLlrp/pqJMz77yIMjAyNuW5tO+8iSIsIHN0dWR5X2lkID0gInN0dWR5MyIpCikgJT4lCiAgZHBseXI6OmZpbHRlcigKICAgIHN0YXR1cyA9PSAiZXN0aW1hdGVkIiwKICAgICFpcy5uYSh0ZXJtKSwKICAgIHRlcm0gIT0gIihJbnRlcmNlcHQpIiwKICAgICFpcy5uYShlc3RpbWF0ZSkKICApICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDlsZ7mgKfooajnpLogPSDlsZ7mgKfml6XmnKzoqp4oYXR0cmlidXRlKSwKICAgIOadoeS7tuihqOekuiA9IHB1cnJyOjptYXAyX2NocihwYXJ0eV9uLCBzdHVkeV9pZCwg5p2h5Lu25pel5pys6KqeKSwKICAgIOawtOa6luihqOekuiA9IOawtOa6luaXpeacrOiqnih0ZXJtLCBsYWJlbCwgYXR0cmlidXRlKSwKICAgIOihqOekuumgheebriA9IHBhc3RlMCjlsZ7mgKfooajnpLosICLvvJoiLCDmsLTmupbooajnpLopCiAgKQoK6KOc5ZuzSDHkvZzmiJAgPC0gZnVuY3Rpb24o5o+P55S744OH44O844K/LCDlrp/pqJPlkI0pIHsKICDpoIXnm67poIYgPC0g5o+P55S744OH44O844K/ICU+JQogICAgZHBseXI6OmRpc3RpbmN0KOWxnuaAp+ihqOekuiwg5rC05rqW6KGo56S6LCDooajnpLrpoIXnm64pICU+JQogICAgZHBseXI6OnB1bGwo6KGo56S66aCF55uuKQoKICDmnaHku7bpoIYgPC0g5o+P55S744OH44O844K/ICU+JQogICAgZHBseXI6OmRpc3RpbmN0KHBhcnR5X24sIOadoeS7tuihqOekuikgJT4lCiAgICBkcGx5cjo6YXJyYW5nZShwYXJ0eV9uKSAlPiUKICAgIGRwbHlyOjpwdWxsKOadoeS7tuihqOekuikKCiAg5o+P55S744OH44O844K/IDwtIOaPj+eUu+ODh+ODvOOCvyAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIOihqOekuumgheebriA9IGZhY3RvcijooajnpLrpoIXnm64sIGxldmVscyA9IHJldijpoIXnm67poIYpKSwKICAgICAg5p2h5Lu26KGo56S6ID0gZmFjdG9yKOadoeS7tuihqOekuiwgbGV2ZWxzID0g5p2h5Lu26aCGKQogICAgKQoKICBkb2RnZSA8LSBnZ3Bsb3QyOjpwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNTIpCgogIGdncGxvdDI6OmdncGxvdCgKICAgIOaPj+eUu+ODh+ODvOOCvywKICAgIGdncGxvdDI6OmFlcygKICAgICAgeCA9IGVzdGltYXRlX3BwLAogICAgICB5ID0g6KGo56S66aCF55uuLAogICAgICBzaGFwZSA9IOadoeS7tuihqOekugogICAgKQogICkgKwogICAgZ2dwbG90Mjo6Z2VvbV92bGluZSgKICAgICAgeGludGVyY2VwdCA9IDAsCiAgICAgIGxpbmV3aWR0aCA9IDAuNDUKICAgICkgKwogICAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcmgoCiAgICAgIGdncGxvdDI6OmFlcygKICAgICAgICB4bWluID0gY29uZi5sb3dfcHAsCiAgICAgICAgeG1heCA9IGNvbmYuaGlnaF9wcAogICAgICApLAogICAgICBoZWlnaHQgPSAwLjEyLAogICAgICBwb3NpdGlvbiA9IGRvZGdlLAogICAgICBsaW5ld2lkdGggPSAwLjU1CiAgICApICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoCiAgICAgIHBvc2l0aW9uID0gZG9kZ2UsCiAgICAgIHNpemUgPSAyLjI1LAogICAgICBmaWxsID0gIndoaXRlIgogICAgKSArCiAgICBnZ3Bsb3QyOjpmYWNldF93cmFwKAogICAgICB+IHBhcnR5X3N1cHBvcnRfaCwKICAgICAgbmNvbCA9IDIsCiAgICAgIHNjYWxlcyA9ICJmcmVlX3kiCiAgICApICsKICAgIGdncGxvdDI6OmxhYnMoCiAgICAgIHRpdGxlID0g5a6f6aiT5ZCNLAogICAgICBzdWJ0aXRsZSA9ICLlkITjg5Hjg43jg6vjga/mlK/mjIHmlL/lhZrliKXjga7mjqjlrprntZDmnpzjgILngrnjga9BTUNF44CB5qiq57ea44GvOTUl5L+h6aC85Yy66ZaT44CCIiwKICAgICAgeCA9ICLpgbjmip7norrnjofjgbjjga7lirnmnpzvvIhwcO+8iSIsCiAgICAgIHkgPSBOVUxMLAogICAgICBzaGFwZSA9ICLpgbjmip7ogqLmlbDmnaHku7YiLAogICAgICBjYXB0aW9uID0gIuWbnuetlOiAheaVsOOBjDQw5Lq65pyq5rqA44Gu5pSv5oyB5pS/5YWaw5fpgbjmip7ogqLmlbDmnaHku7bjga/mjqjlrprlr77osaHlpJbjgIIiCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwLjUpICsKICAgIGdncGxvdDI6OnRoZW1lKAogICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGdncGxvdDI6OmVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgIHN0cmlwLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEwLjUpLAogICAgICBheGlzLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gOC42LCBjb2xvciA9ICJibGFjayIpLAogICAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLAogICAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICBwbG90LnN1YnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSA5LjUpLAogICAgICBwbG90LmNhcHRpb24gPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gOC41KSwKICAgICAgcGFuZWwuc3BhY2luZyA9IGdyaWQ6OnVuaXQoMS4wLCAibGluZXMiKQogICAgKQp9CgrooahIMeS9nOaIkCA8LSBmdW5jdGlvbijooajjg4fjg7zjgr8pIHsKICDmlK/mjIHpoIYgPC0gdW5pcXVlKOihqOODh+ODvOOCvyRwYXJ0eV9zdXBwb3J0X2gpCiAg6aCF55uu6aCGIDwtIHVuaXF1ZSjooajjg4fjg7zjgr8k6KGo56S66aCF55uuKQoKICDooajjg4fjg7zjgr8gJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICDmlK/mjIHmlL/lhZogPSBmYWN0b3IocGFydHlfc3VwcG9ydF9oLCBsZXZlbHMgPSDmlK/mjIHpoIYpLAogICAgICBg5bGe5oCn44O75rC05rqWYCA9IGZhY3RvcijooajnpLrpoIXnm64sIGxldmVscyA9IOmgheebrumghiksCiAgICAgIOe1kOaenCA9IHNwcmludGYoCiAgICAgICAgIiUuMmYgWyUuMmYsICUuMmZdIiwKICAgICAgICBlc3RpbWF0ZV9wcCwKICAgICAgICBjb25mLmxvd19wcCwKICAgICAgICBjb25mLmhpZ2hfcHAKICAgICAgKQogICAgKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoCiAgICAgIOaUr+aMgeaUv+WFmiwKICAgICAgYOWxnuaAp+ODu+awtOa6lmAsCiAgICAgIOadoeS7tiA9IOadoeS7tuihqOekuiwKICAgICAg57WQ5p6cCiAgICApICU+JQogICAgdGlkeXI6OnBpdm90X3dpZGVyKAogICAgICBuYW1lc19mcm9tID0g5p2h5Lu2LAogICAgICB2YWx1ZXNfZnJvbSA9IOe1kOaenCwKICAgICAgdmFsdWVzX2ZpbGwgPSAi4oCUIgogICAgKSAlPiUKICAgIGRwbHlyOjphcnJhbmdlKOaUr+aMgeaUv+WFmiwgYOWxnuaAp+ODu+awtOa6lmApICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAg5pSv5oyB5pS/5YWaID0gYXMuY2hhcmFjdGVyKOaUr+aMgeaUv+WFmiksCiAgICAgIGDlsZ7mgKfjg7vmsLTmupZgID0gYXMuY2hhcmFjdGVyKGDlsZ7mgKfjg7vmsLTmupZgKQogICAgKQp9CgrooahIMeWbnuetlOiAheaVsOS9nOaIkCA8LSBmdW5jdGlvbijooajjg4fjg7zjgr8pIHsKICDooajjg4fjg7zjgr8gJT4lCiAgICBkcGx5cjo6ZGlzdGluY3QoCiAgICAgIOaUr+aMgeaUv+WFmiA9IHBhcnR5X3N1cHBvcnRfaCwKICAgICAg5p2h5Lu2ID0g5p2h5Lu26KGo56S6LAogICAgICDlm57nrZTogIXmlbAgPSBuX2lkcwogICAgKSAlPiUKICAgIGRwbHlyOjptdXRhdGUo5Zue562U6ICF5pWwID0gYXMuY2hhcmFjdGVyKOWbnuetlOiAheaVsCkpICU+JQogICAgdGlkeXI6OnBpdm90X3dpZGVyKAogICAgICBuYW1lc19mcm9tID0g5p2h5Lu2LAogICAgICB2YWx1ZXNfZnJvbSA9IOWbnuetlOiAheaVsCwKICAgICAgdmFsdWVzX2ZpbGwgPSAi4oCUIgogICAgKSAlPiUKICAgIGRwbHlyOjphcnJhbmdlKOaUr+aMgeaUv+WFmikKfQpgYGAKCiMjIyDoo5zlm7NIMWHvvJrlrp/pqJMx77yIMjAyM+W5tO+8iQoK5a6f6aiTMeOBq+OBpOOBhOOBpuOAgeaOqOWumuWPr+iDveOBp+OBguOBo+OBn+aUr+aMgeaUv+WFmuWIpeOBq0FNQ0XjgpLnpLrjgZnjgILlkITjg5Hjg43jg6vlhoXjgafjga/jgIHlkIzkuIDjga7lsZ7mgKfjg7vmsLTmupbjgavjgaTjgYTjgaY044Gk44Gu5pS/5YWa5pWw5p2h5Lu244KS5q+U6LyD44Gn44GN44KL44CCCgpgYGB7ciBnMS1zdHVkeTEtZmlndXJlLCBlY2hvPVRSVUUsIGV2YWw9VFJVRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTkuNSwgb3V0LndpZHRoPScxMDAlJ30KSDFf5a6f6aiTMSA8LSDmlK/mjIFBTUNF5LiA6KanICU+JQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfaWQgPT0gInN0dWR5MSIpCgroo5zlm7NIMWEgPC0g6KOc5ZuzSDHkvZzmiJAoCiAgSDFf5a6f6aiTMSwKICAi6KOc5ZuzSDFh77ya5a6f6aiTMe+8iDIwMjPlubTvvInjga7mlK/mjIHmlL/lhZrliKVBTUNFIgopCuijnOWbs0gxYQpgYGAKCuWvvuW/nOOBmeOCi+WbnuetlOiAheaVsOOBqEFNQ0XjgpLku6XkuIvjgavnpLrjgZnjgIJBTUNF6KGo44Gn44Gv44CB5ZCE5p2h5Lu244Gu54K55o6o5a6a5YCk44GoOTUl5L+h6aC85Yy66ZaT44KSMeOCu+ODq+OBq+OBvuOBqOOCgeOBpuOBhOOCi+OAggoKYGBge3IgZzEtc3R1ZHkxLXRhYmxlLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KGoSDFh5Zue562U6ICF5pWwIDwtIOihqEgx5Zue562U6ICF5pWw5L2c5oiQKEgxX+Wun+mokzEpCmtuaXRyOjprYWJsZSgKICDooahIMWHlm57nrZTogIXmlbAsCiAgZm9ybWF0ID0gImh0bWwiLAogIHJvdy5uYW1lcyA9IEZBTFNFLAogIHRhYmxlLmF0dHIgPSAnY2xhc3M9InRhYmxlIHRhYmxlLWNvbmRlbnNlZCIgc3R5bGU9ImZvbnQtc2l6ZTo5MCU7IicsCiAgY2FwdGlvbiA9ICLooahIMWEtMe+8muWun+mokzHvvIgyMDIz5bm077yJ44Gu5pSv5oyB5pS/5YWa5Yil5Zue562U6ICF5pWwIgopCgrooahIMWEgPC0g6KGoSDHkvZzmiJAoSDFf5a6f6aiTMSkKa25pdHI6OmthYmxlKAogIOihqEgxYSwKICBmb3JtYXQgPSAiaHRtbCIsCiAgcm93Lm5hbWVzID0gRkFMU0UsCiAgdGFibGUuYXR0ciA9ICdjbGFzcz0idGFibGUgdGFibGUtY29uZGVuc2VkIiBzdHlsZT0iZm9udC1zaXplOjkwJTsiJywKICBjYXB0aW9uID0gIuihqEgxYS0y77ya5a6f6aiTMe+8iDIwMjPlubTvvInjga7mlK/mjIHmlL/lhZrliKVBTUNF77y754K55o6o5a6a5YCkIFs5NSUgQ0ld44CBcHDvvL0iCikKYGBgCgojIyMg6KOc5ZuzSDFi77ya5a6f6aiTMu+8iDIwMjblubTvvIkKCuWun+mokzLjgavjgaTjgYTjgabjgoLlkIzjgZjlvaLlvI/jgafnpLrjgZnjgILmlK/mjIHmlL/lhZrjga7nqK7poZ7jgYzlrp/pqJMx44KI44KK5aSa44GE44Gf44KB44CB5pSv5oyB5pS/5YWa44KSMuWIl+OBruODleOCoeOCu+ODg+ODiOOBq+WIhuOBkeOAgeWQhOODkeODjeODq+OBp+WxnuaAp+ODu+awtOa6luOCkue4puaWueWQkeOBq+i/veOBiOOCi+OCiOOBhuOBq+OBl+OBn+OAggoKYGBge3IgZzEtc3R1ZHkyLWZpZ3VyZSwgZWNobz1UUlVFLCBldmFsPVRSVUUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xNiwgb3V0LndpZHRoPScxMDAlJ30KSDFf5a6f6aiTMiA8LSDmlK/mjIFBTUNF5LiA6KanICU+JQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfaWQgPT0gInN0dWR5MiIpCgroo5zlm7NIMWIgPC0g6KOc5ZuzSDHkvZzmiJAoCiAgSDFf5a6f6aiTMiwKICAi6KOc5ZuzSDFi77ya5a6f6aiTMu+8iDIwMjblubTvvInjga7mlK/mjIHmlL/lhZrliKVBTUNFIgopCuijnOWbs0gxYgpgYGAKCmBgYHtyIGcxLXN0dWR5Mi10YWJsZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuihqEgxYuWbnuetlOiAheaVsCA8LSDooahIMeWbnuetlOiAheaVsOS9nOaIkChIMV/lrp/pqJMyKQprbml0cjo6a2FibGUoCiAg6KGoSDFi5Zue562U6ICF5pWwLAogIGZvcm1hdCA9ICJodG1sIiwKICByb3cubmFtZXMgPSBGQUxTRSwKICB0YWJsZS5hdHRyID0gJ2NsYXNzPSJ0YWJsZSB0YWJsZS1jb25kZW5zZWQiIHN0eWxlPSJmb250LXNpemU6OTAlOyInLAogIGNhcHRpb24gPSAi6KGoSDFiLTHvvJrlrp/pqJMy77yIMjAyNuW5tO+8ieOBruaUr+aMgeaUv+WFmuWIpeWbnuetlOiAheaVsCIKKQoK6KGoSDFiIDwtIOihqEgx5L2c5oiQKEgxX+Wun+mokzIpCmtuaXRyOjprYWJsZSgKICDooahIMWIsCiAgZm9ybWF0ID0gImh0bWwiLAogIHJvdy5uYW1lcyA9IEZBTFNFLAogIHRhYmxlLmF0dHIgPSAnY2xhc3M9InRhYmxlIHRhYmxlLWNvbmRlbnNlZCIgc3R5bGU9ImZvbnQtc2l6ZTo5MCU7IicsCiAgY2FwdGlvbiA9ICLooahIMWItMu+8muWun+mokzLvvIgyMDI25bm077yJ44Gu5pSv5oyB5pS/5YWa5YilQU1DRe+8u+eCueaOqOWumuWApCBbOTUlIENJXeOAgXBw77y9IgopCmBgYAoKIyMjIOijnOWbs0gxY++8muWun+mokzPvvIgyMDI25bm077yJCgrlrp/pqJMz44Gn44Gv44CB5pS/5YWa5bGe5oCn44GM5pS/5YWa5ZCN44Go44GX44Gm5o+Q56S644GV44KM44KL44CC5Zuz44Gu5qeL5oiQ44Gv5a6f6aiTMeODuzLjgajmj4PjgYjjgIHmlK/mjIHmlL/lhZrjgZTjgajjgavjgIHmlL/lhZrlkI3jgYrjgojjgbPntYzmuIjlsZ7mgKfjga7lkITmsLTmupbjgavlr77jgZnjgotBTUNF44KS5q+U6LyD44Gn44GN44KL44KI44GG44Gr44GX44Gf44CCCgpgYGB7ciBnMS1zdHVkeTMtZmlndXJlLCBlY2hvPVRSVUUsIGV2YWw9VFJVRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTE2LCBvdXQud2lkdGg9JzEwMCUnfQpIMV/lrp/pqJMzIDwtIOaUr+aMgUFNQ0XkuIDopqcgJT4lCiAgZHBseXI6OmZpbHRlcihzdHVkeV9pZCA9PSAic3R1ZHkzIikKCuijnOWbs0gxYyA8LSDoo5zlm7NIMeS9nOaIkCgKICBIMV/lrp/pqJMzLAogICLoo5zlm7NIMWPvvJrlrp/pqJMz77yIMjAyNuW5tO+8ieOBruaUr+aMgeaUv+WFmuWIpUFNQ0UiCikK6KOc5ZuzSDFjCmBgYAoKYGBge3IgZzEtc3R1ZHkzLXRhYmxlLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K6KGoSDFj5Zue562U6ICF5pWwIDwtIOihqEgx5Zue562U6ICF5pWw5L2c5oiQKEgxX+Wun+mokzMpCmtuaXRyOjprYWJsZSgKICDooahIMWPlm57nrZTogIXmlbAsCiAgZm9ybWF0ID0gImh0bWwiLAogIHJvdy5uYW1lcyA9IEZBTFNFLAogIHRhYmxlLmF0dHIgPSAnY2xhc3M9InRhYmxlIHRhYmxlLWNvbmRlbnNlZCIgc3R5bGU9ImZvbnQtc2l6ZTo5MCU7IicsCiAgY2FwdGlvbiA9ICLooahIMWMtMe+8muWun+mokzPvvIgyMDI25bm077yJ44Gu5pSv5oyB5pS/5YWa5Yil5Zue562U6ICF5pWwIgopCgrooahIMWMgPC0g6KGoSDHkvZzmiJAoSDFf5a6f6aiTMykKa25pdHI6OmthYmxlKAogIOihqEgxYywKICBmb3JtYXQgPSAiaHRtbCIsCiAgcm93Lm5hbWVzID0gRkFMU0UsCiAgdGFibGUuYXR0ciA9ICdjbGFzcz0idGFibGUgdGFibGUtY29uZGVuc2VkIiBzdHlsZT0iZm9udC1zaXplOjkwJTsiJywKICBjYXB0aW9uID0gIuihqEgxYy0y77ya5a6f6aiTM++8iDIwMjblubTvvInjga7mlK/mjIHmlL/lhZrliKVBTUNF77y754K55o6o5a6a5YCkIFs5NSUgQ0ld44CBcHDvvL0iCikKYGBgCgojIyDoo5zlm7NIMu+8muaUr+aMgeaUv+WFmuWIpeOBruaJi+OBjOOBi+OCiumHjeimgeW6puOBqOebuOWvvuavlOmHjQoKYGBge3IgZzIsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrmlK/mjIHmiYvjgYzjgYvjgorkuIDopqcgPC0gZHBseXI6OmJpbmRfcm93cygKICBwYXJ0eV9zdXBwb3J0X3JlbGF0aXZlX2N1ZV9yZXN1bHRzJHN0dWR5MSRpbnRlcnZhbHMgJT4lIGRwbHlyOjptdXRhdGUo5a6f6aiTID0gIuWun+mokzHvvIgyMDIz5bm077yJIiwgc3R1ZHlfaWQgPSAic3R1ZHkxIiksCiAgcGFydHlfc3VwcG9ydF9yZWxhdGl2ZV9jdWVfcmVzdWx0cyRzdHVkeTIkaW50ZXJ2YWxzICU+JSBkcGx5cjo6bXV0YXRlKOWun+mokyA9ICLlrp/pqJMy77yIMjAyNuW5tO+8iSIsIHN0dWR5X2lkID0gInN0dWR5MiIpLAogIHBhcnR5X3N1cHBvcnRfcmVsYXRpdmVfY3VlX3Jlc3VsdHMkc3R1ZHkzJGludGVydmFscyAlPiUgZHBseXI6Om11dGF0ZSjlrp/pqJMgPSAi5a6f6aiTM++8iDIwMjblubTvvIkiLCBzdHVkeV9pZCA9ICJzdHVkeTMiKQopICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDmnaHku7YgPSBwdXJycjo6bWFwMl9jaHIocGFydHlfbiwgc3R1ZHlfaWQsIOadoeS7tuaXpeacrOiqniksCiAgICDmjIfmqJkgPSBwdXJycjo6bWFwMl9jaHIoc3RhdGlzdGljLCBzdHVkeV9pZCwg57Wx6KiI6YeP5pel5pys6KqeKSwKICAgIOihqOekuuWApCA9IGRwbHlyOjppZl9lbHNlKHN0YXRpc3RpYyA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIiwgMTAwICogZXN0aW1hdGUsIDEwMCAqIGVzdGltYXRlKSwKICAgIOS4i+mZkCA9IDEwMCAqIGNvbmZfbG93LAogICAg5LiK6ZmQID0gMTAwICogY29uZl9oaWdoLAogICAg5Y2Y5L2NID0gZHBseXI6OmlmX2Vsc2Uoc3RhdGlzdGljID09ICJyZWxhdGl2ZV9wYXJ0eV93ZWlnaHRfcGFpcndpc2UiLCAiJSIsICJwcCIpCiAgKQoK55u45a++5q+U6YeN44OH44O844K/IDwtIOaUr+aMgeaJi+OBjOOBi+OCiuS4gOimpyAlPiUKICBkcGx5cjo6ZmlsdGVyKHN0YXRpc3RpYyA9PSAicmVsYXRpdmVfcGFydHlfd2VpZ2h0X3BhaXJ3aXNlIikgJT4lCiAgZHBseXI6Om11dGF0ZSjmlbDlgKTjg6njg5njg6sgPSBzcHJpbnRmKCIlLjFmJSUiLCDooajnpLrlgKQpKQoKZm9yICjlrp/pqJPlkI0gaW4gdW5pcXVlKOebuOWvvuavlOmHjeODh+ODvOOCvyTlrp/pqJMpKSB7CiAg5o+P55S744OH44O844K/IDwtIOebuOWvvuavlOmHjeODh+ODvOOCvyAlPiUgZHBseXI6OmZpbHRlcijlrp/pqJMgPT0g5a6f6aiT5ZCNKQogIOWbsyA8LSBnZ3Bsb3QyOjpnZ3Bsb3Qo5o+P55S744OH44O844K/LCBnZ3Bsb3QyOjphZXMoeCA9IHBhcnR5X24sIHkgPSDooajnpLrlgKQsIGdyb3VwID0gcGFydHlfc3VwcG9ydF9oKSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDAuNCkgKwogICAgZ2dwbG90Mjo6Z2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuNjUpICsKICAgIGdncGxvdDI6Omdlb21fZXJyb3JiYXIoZ2dwbG90Mjo6YWVzKHltaW4gPSDkuIvpmZAsIHltYXggPSDkuIrpmZApLCB3aWR0aCA9IDAuMDgsIGxpbmV3aWR0aCA9IDAuNDUpICsKICAgIGdncGxvdDI6Omdlb21fbGFiZWwoZ2dwbG90Mjo6YWVzKGxhYmVsID0g5pWw5YCk44Op44OZ44OrKSwgc2l6ZSA9IDMuMCwgbGFiZWwuc2l6ZSA9IDAsIGZpbGwgPSAid2hpdGUiKSArCiAgICBnZ3Bsb3QyOjpmYWNldF93cmFwKH4gcGFydHlfc3VwcG9ydF9oLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDI6NSwgbGFiZWxzID0g5p2h5Lu25pel5pys6KqeKDI6NSwgaWZlbHNlKHVuaXF1ZSjmj4/nlLvjg4fjg7zjgr8kc3R1ZHlfaWQpID09ICJzdHVkeTMiLCAic3R1ZHkzIiwgInN0dWR5MSIpKSkgKwogICAgZ2dwbG90Mjo6bGFicyh4ID0gTlVMTCwgeSA9ICLmlL/lhZrmiYvjgYzjgYvjgornm7jlr77mr5Tph43vvIgl77yJIiwgc3VidGl0bGUgPSDlrp/pqJPlkI0pICsKICAgIGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwKSArCiAgICBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpKQogIHByaW50KOWbsykKfQoK6KGoSDIgPC0g5pSv5oyB5omL44GM44GL44KK5LiA6KanICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDlrp/pqJMsCiAgICDmlK/mjIHmlL/lhZogPSBwYXJ0eV9zdXBwb3J0X2gsCiAgICBg5p2h5Lu244O75oyH5qiZYCA9IHBhc3RlMCjmnaHku7YsICLvvJoiLCDmjIfmqJkpLAogICAg5o6o5a6a5YCkID0gcm91bmQo6KGo56S65YCkLCAyKSwKICAgIGA5NSVDSeS4i+mZkGAgPSByb3VuZCjkuIvpmZAsIDIpLAogICAgYDk1JUNJ5LiK6ZmQYCA9IHJvdW5kKOS4iumZkCwgMiksCiAgICDljZjkvY0KICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoSDIpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIuihqEgy77ya5pSv5oyB5pS/5YWa5Yil44Gu5omL44GM44GL44KK6YeN6KaB5bqm44Go55u45a++5q+U6YeNIikKYGBgCgojIyDoo5zlm7NIM++8muWvvuixoeOBqOOBquOCi+aUr+aMgeaUv+WFmuWIpeOBruS4gOiHtOWKueaenAoKYGBge3IgZzMsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQrkuIDoh7TlirnmnpwgPC0gc3R1ZHkzX2FsbF9wYXJ0eV9tYXRjaF9yZXN1bHRzJGNvZWZmaWNpZW50cyAlPiUKICBkcGx5cjo6ZmlsdGVyKHN0YXR1cyA9PSAiZXN0aW1hdGVkIiwgIWlzLm5hKGVzdGltYXRlKSkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOadoeS7tiA9IOadoeS7tuaXpeacrOiqnihwYXJ0eV9uLCAic3R1ZHkzIiksCiAgICDmlbDlgKTjg6njg5njg6sgPSBzcHJpbnRmKCIlLjFmIiwgZXN0aW1hdGVfcHApCiAgKQoK6KOc5ZuzSDMgPC0gZ2dwbG90Mjo6Z2dwbG90KOS4gOiHtOWKueaenCwgZ2dwbG90Mjo6YWVzKHggPSBwYXJ0eV9uLCB5ID0gZXN0aW1hdGVfcHAsIGdyb3VwID0gMSkpICsKICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjQpICsKICBnZ3Bsb3QyOjpnZW9tX2xpbmUobGluZXdpZHRoID0gMC42NSkgKwogIGdncGxvdDI6Omdlb21fZXJyb3JiYXIoZ2dwbG90Mjo6YWVzKHltaW4gPSBjb25mLmxvd19wcCwgeW1heCA9IGNvbmYuaGlnaF9wcCksIHdpZHRoID0gMC4wOCwgbGluZXdpZHRoID0gMC40NSkgKwogIGdncGxvdDI6Omdlb21fbGFiZWwoZ2dwbG90Mjo6YWVzKGxhYmVsID0g5pWw5YCk44Op44OZ44OrKSwgc2l6ZSA9IDMuMCwgbGFiZWwuc2l6ZSA9IDAsIGZpbGwgPSAid2hpdGUiKSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IHN1cHBvcnRfcGFydHlfdmFsaWQpICsKICBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMjo1LCBsYWJlbHMgPSBwYXN0ZTAoMjo1LCAi6YG45oqe6IKiIikpICsKICBnZ3Bsb3QyOjpsYWJzKHggPSAi6YG45oqe6IKi5pWwIiwgeSA9ICLkuIDoh7TlirnmnpzvvIhwcO+8iSIpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMCkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCkpCuijnOWbs0gzCgrooahIMyA8LSDkuIDoh7TlirnmnpwgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOaUr+aMgeaUv+WFmiA9IHN1cHBvcnRfcGFydHlfdmFsaWQsCiAgICDmnaHku7YsCiAgICDlm57nrZTogIXmlbAgPSBuX2lkcywKICAgIGDkuIDoh7TlirnmnpzvvIhwcO+8iWAgPSByb3VuZChlc3RpbWF0ZV9wcCwgMiksCiAgICBgOTUlQ0nkuIvpmZBgID0gcm91bmQoY29uZi5sb3dfcHAsIDIpLAogICAgYDk1JUNJ5LiK6ZmQYCA9IHJvdW5kKGNvbmYuaGlnaF9wcCwgMiksCiAgICBw5YCkID0gc2lnbmlmKHAudmFsdWUsIDMpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEgzKSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKCuihqEg0IDwtIHN0dWR5M19hbGxfcGFydHlfbWF0Y2hfcmVzdWx0cyR0cmVuZHMgJT4lCiAgZHBseXI6OmZpbHRlcihzdGF0dXMgPT0gImVzdGltYXRlZCIpICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDmlK/mjIHmlL/lhZogPSBzdXBwb3J0X3BhcnR5X3ZhbGlkLAogICAgYDHpgbjmip7ogqLlopfliqDjgYLjgZ/jgorjga7lpInljJbvvIhwcO+8iWAgPSByb3VuZChlc3RpbWF0ZSAqIDEwMCwgMiksCiAgICBgOTUlQ0nkuIvpmZBgID0gcm91bmQoY29uZi5sb3cgKiAxMDAsIDIpLAogICAgYDk1JUNJ5LiK6ZmQYCA9IHJvdW5kKGNvbmYuaGlnaCAqIDEwMCwgMiksCiAgICBw5YCkID0gc2lnbmlmKHAudmFsdWUsIDMpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEg0KSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIEkuIDPlrp/pqJPmqKrmlq3liIbmnpAKCiMjIOijnOWbs0kx77ya5Li76KaB5Luu6Kqs44Gu57ea5b2i5YK+5ZCRCgpgYGB7ciBoMSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CuS4u+imgeS7ruiqrCA8LSBoeXBvdGhlc2lzX3Rlc3Rfc3VtbWFyeSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAg5a6f6aiTID0gZHBseXI6OnJlY29kZShzdHVkeV9pZCwgc3R1ZHkxID0gIuWun+mokzHvvIgyMDIz5bm077yJIiwgc3R1ZHkyID0gIuWun+mokzLvvIgyMDI25bm077yJIiwgc3R1ZHkzID0gIuWun+mokzPvvIgyMDI25bm077yJIiksCiAgICDmjIfmqJkgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHN0YXRpc3RpYywgInBhcnR5IikgfiAi5pS/5YWa5omL44GM44GL44KK6YeN6KaB5bqmIiwKICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdChzdGF0aXN0aWMsICJlY29ub21pYyIpIH4gIue1jOa4iOaJi+OBjOOBi+OCiumHjeimgeW6piIsCiAgICAgIFRSVUUgfiBzdGF0aXN0aWMKICAgICksCiAgICDkuojmuKzmlrnlkJEgPSBkcGx5cjo6cmVjb2RlKGV4cGVjdGVkX2RpcmVjdGlvbiwgcG9zaXRpdmUgPSAi5q2jIiwgbmVnYXRpdmUgPSAi6LKgIikKICApCgrkuLvopoHku67oqqwgPC0g5Li76KaB5Luu6KqsICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDlgr7jgY1wcCA9IDEwMCAqIGVzdGltYXRlLAogICAg5LiL6ZmQcHAgPSAxMDAgKiBjb25mX2xvdywKICAgIOS4iumZkHBwID0gMTAwICogY29uZl9oaWdoLAogICAg6KGo56S66KGMID0gcGFzdGUwKGh5cG90aGVzaXMsICLvvJoiLCDmjIfmqJkpLAogICAg5pWw5YCk44Op44OZ44OrID0gc3ByaW50ZigiJS4yZiIsIOWCvuOBjXBwKQogICkKCuijnOWbs0kxIDwtIGdncGxvdDI6OmdncGxvdCjkuLvopoHku67oqqwsIGdncGxvdDI6OmFlcyh4ID0g5YK+44GNcHAsIHkgPSBzdGF0czo6cmVvcmRlcijooajnpLrooYwsIOWCvuOBjXBwKSkpICsKICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ld2lkdGggPSAwLjQ1KSArCiAgZ2dwbG90Mjo6Z2VvbV9lcnJvcmJhcmgoZ2dwbG90Mjo6YWVzKHhtaW4gPSDkuIvpmZBwcCwgeG1heCA9IOS4iumZkHBwKSwgaGVpZ2h0ID0gMC4xMiwgbGluZXdpZHRoID0gMC41NSkgKwogIGdncGxvdDI6Omdlb21fbGFiZWwoZ2dwbG90Mjo6YWVzKGxhYmVsID0g5pWw5YCk44Op44OZ44OrKSwgc2l6ZSA9IDMuMSwgbGFiZWwuc2l6ZSA9IDAsIGZpbGwgPSAid2hpdGUiKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIumBuOaKnuiCouOBjDHjgaTlopfjgYjjgovjgajjgY3jga7ph43opoHluqbjga7lpInljJbvvIhwcO+8iSIsIHkgPSBOVUxMKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTEpICsKICBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpKQroo5zlm7NJMQoK6KGoSTEgPC0g5Li76KaB5Luu6KqsICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDlrp/pqJMsCiAgICDku67oqqwgPSBoeXBvdGhlc2lzLAogICAg5oyH5qiZLAogICAg5LqI5ris5pa55ZCRLAogICAg5YK+44GNID0gcm91bmQoZXN0aW1hdGUsIDQpLAogICAgYDk1JUNJ5LiL6ZmQYCA9IHJvdW5kKGNvbmZfbG93LCA0KSwKICAgIGA5NSVDSeS4iumZkGAgPSByb3VuZChjb25mX2hpZ2gsIDQpLAogICAgcOWApCA9IHNpZ25pZihwX3ZhbHVlX3R3b19zaWRlZCwgMyksCiAgICDliKTlrpogPSBjb25jbHVzaW9uCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEkxKSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyDoo5zlm7NJMu+8mumBuOaKnuiCouaVsOiqv+aVtOa4iOOBv+mHjeimgeW6puOBrue3muW9ouWCvuWQkQoKYGBge3IgaDIsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQroqr/mlbTmuIjjgb/lgr7lkJEgPC0gY2hvaWNlX3NldF9hZGp1c3RlZF9zbG9wZV9zdW1tYXJ5ICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICDlrp/pqJMgPSBkcGx5cjo6cmVjb2RlKHN0dWR5X2lkLCBzdHVkeTEgPSAi5a6f6aiTMe+8iDIwMjPlubTvvIkiLCBzdHVkeTIgPSAi5a6f6aiTMu+8iDIwMjblubTvvIkiLCBzdHVkeTMgPSAi5a6f6aiTM++8iDIwMjblubTvvIkiKSwKICAgIOaMh+aomSA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3Qoc3RhdGlzdGljLCAicGFydHkiKSB+ICLmlL/lhZrmiYvjgYzjgYvjgorph43opoHluqbvvIjpgbjmip7ogqLmlbDoqr/mlbTmuIjjgb/vvIkiLAogICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHN0YXRpc3RpYywgImVjb25vbWljIikgfiAi57WM5riI5omL44GM44GL44KK6YeN6KaB5bqm77yI6YG45oqe6IKi5pWw6Kq/5pW05riI44G/77yJIiwKICAgICAgVFJVRSB+IHN0YXRpc3RpYwogICAgKQogICkKCuiqv+aVtOa4iOOBv+WCvuWQkSA8LSDoqr/mlbTmuIjjgb/lgr7lkJEgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIOWCvuOBjeihqOekuiA9IDEwMCAqIGVzdGltYXRlLAogICAg5LiL6ZmQ6KGo56S6ID0gMTAwICogY29uZl9sb3csCiAgICDkuIrpmZDooajnpLogPSAxMDAgKiBjb25mX2hpZ2gsCiAgICDooajnpLrooYwgPSBwYXN0ZTAo5a6f6aiTLCAi77yaIiwg5oyH5qiZKSwKICAgIOaVsOWApOODqeODmeODqyA9IHNwcmludGYoIiUuMmYiLCDlgr7jgY3ooajnpLopCiAgKQoK6KOc5ZuzSTIgPC0gZ2dwbG90Mjo6Z2dwbG90KOiqv+aVtOa4iOOBv+WCvuWQkSwgZ2dwbG90Mjo6YWVzKHggPSDlgr7jgY3ooajnpLosIHkgPSBzdGF0czo6cmVvcmRlcijooajnpLrooYwsIOWCvuOBjeihqOekuikpKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXdpZHRoID0gMC40NSkgKwogIGdncGxvdDI6Omdlb21fZXJyb3JiYXJoKGdncGxvdDI6OmFlcyh4bWluID0g5LiL6ZmQ6KGo56S6LCB4bWF4ID0g5LiK6ZmQ6KGo56S6KSwgaGVpZ2h0ID0gMC4xMiwgbGluZXdpZHRoID0gMC41NSkgKwogIGdncGxvdDI6Omdlb21fbGFiZWwoZ2dwbG90Mjo6YWVzKGxhYmVsID0g5pWw5YCk44Op44OZ44OrKSwgc2l6ZSA9IDMuMSwgbGFiZWwuc2l6ZSA9IDAsIGZpbGwgPSAid2hpdGUiKSArCiAgZ2dwbG90Mjo6bGFicyh4ID0gIumBuOaKnuiCouOBjDHjgaTlopfjgYjjgovjgajjgY3jga7oqr/mlbTmuIjjgb/ph43opoHluqbjga7lpInljJbvvIgl77yJIiwgeSA9IE5VTEwpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCkpCuijnOWbs0kyCgrooahJMiA8LSDoqr/mlbTmuIjjgb/lgr7lkJEgJT4lCiAgZHBseXI6OnRyYW5zbXV0ZSgKICAgIOWun+mokywKICAgIOaMh+aomSwKICAgIOWCvuOBjSA9IHJvdW5kKGVzdGltYXRlLCA0KSwKICAgIGA5NSVDSeS4i+mZkGAgPSByb3VuZChjb25mX2xvdywgNCksCiAgICBgOTUlQ0nkuIrpmZBgID0gcm91bmQoY29uZl9oaWdoLCA0KSwKICAgIHDlgKQgPSBzaWduaWYocF92YWx1ZV90d29fc2lkZWQsIDMpCiAgKQprbml0cjo6a2FibGUo6KGo5pel5pys6KqeKOihqEkyKSwgZm9ybWF0ID0gImh0bWwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyDoo5zlm7NJM++8muaUv+WFmuaJi+OBjOOBi+OCiuebuOWvvuavlOmHjeOBrjPlrp/pqJPmr5TovIMKCmBgYHtyIGgzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0K5qiq5pat55u45a++5q+U6YeNIDwtIGNyb3NzX3N0dWR5X3JlbGF0aXZlX3dlaWdodCAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAg5a6f6aiTID0gZHBseXI6OnJlY29kZShzdHVkeV9pZCwgc3R1ZHkxID0gIuWun+mokzHvvIgyMDIz5bm077yJIiwgc3R1ZHkyID0gIuWun+mokzLvvIgyMDI25bm077yJIiwgc3R1ZHkzID0gIuWun+mokzPvvIgyMDI25bm077yJIiksCiAgICDnm7jlr77mr5Tph40gPSAxMDAgKiBlc3RpbWF0ZSwKICAgIOS4i+mZkCA9IDEwMCAqIGNvbmZfbG93LAogICAg5LiK6ZmQID0gMTAwICogY29uZl9oaWdoLAogICAg5pWw5YCk44Op44OZ44OrID0gc3ByaW50ZigiJS4xZiUlIiwg55u45a++5q+U6YeNKQogICkKCuijnOWbs0kzIDwtIGdncGxvdDI6OmdncGxvdCjmqKrmlq3nm7jlr77mr5Tph40sIGdncGxvdDI6OmFlcyh4ID0gcGFydHlfbiwgeSA9IOebuOWvvuavlOmHjSwgZ3JvdXAgPSDlrp/pqJMsIGxpbmV0eXBlID0g5a6f6aiTKSkgKwogIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAwLjQpICsKICBnZ3Bsb3QyOjpnZW9tX2xpbmUobGluZXdpZHRoID0gMC43NSkgKwogIGdncGxvdDI6Omdlb21fZXJyb3JiYXIoZ2dwbG90Mjo6YWVzKHltaW4gPSDkuIvpmZAsIHltYXggPSDkuIrpmZApLCB3aWR0aCA9IDAuMDcsIGxpbmV3aWR0aCA9IDAuNDUpICsKICBnZ3Bsb3QyOjpnZW9tX2xhYmVsKGdncGxvdDI6OmFlcyhsYWJlbCA9IOaVsOWApOODqeODmeODqyksIHNpemUgPSAzLjAsIGxhYmVsLnNpemUgPSAwLCBmaWxsID0gIndoaXRlIikgKwogIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAyOjUsIGxhYmVscyA9IHBhc3RlMCgyOjUsICLpgbjmip7ogqIiKSkgKwogIGdncGxvdDI6OmxhYnMoeCA9ICLpgbjmip7ogqLmlbAiLCB5ID0gIuaUv+WFmuaJi+OBjOOBi+OCiuebuOWvvuavlOmHje+8iCXvvIkiLCBsaW5ldHlwZSA9IE5VTEwpICsKICBnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMSkgKwogIGdncGxvdDI6OnRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQroo5zlm7NJMwoK6KGoSTMgPC0g5qiq5pat55u45a++5q+U6YeNICU+JQogIGRwbHlyOjp0cmFuc211dGUoCiAgICDlrp/pqJMsCiAgICDmnaHku7YgPSBwYXN0ZTAocGFydHlfbiwgIumBuOaKnuiCouadoeS7tiIpLAogICAgYOaUv+WFmuaJi+OBjOOBi+OCiuebuOWvvuavlOmHje+8iCXvvIlgID0gcm91bmQo55u45a++5q+U6YeNLCAxKSwKICAgIGA5NSVDSeS4i+mZkGAgPSByb3VuZCjkuIvpmZAsIDEpLAogICAgYDk1JUNJ5LiK6ZmQYCA9IHJvdW5kKOS4iumZkCwgMSkKICApCmtuaXRyOjprYWJsZSjooajml6XmnKzoqp4o6KGoSTMpLCBmb3JtYXQgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAK