Appendix S10: Codes for used statistical analyses

Title: A workflow to optimize spatial sampling in ecoacoustic studies
Journal: Landscape Ecology

Authors:
Martínez-Arias, V. M.; Paniagua-Villada, C.; Daza, J. M.

Author affiliations at the time the work was conducted:
1. Grupo Herpetológico de Antioquia, Calle 70 No. 52 - 21, Postal Code 050010, Medellín, Colombia.

Corresponding author:
Victor M. Martínez-Arias
📧 Email:
📞 Tel: +57 311 679 7846

0. Exploration graphic

This graphic allow to visually compare the indices in the range 0-24khz, for all hours and localities. We did not use it

library(ggplot2)
library(readxl)
library(dplyr)

Statistic <- "mean"  # Set to "mean" or "median"
# Load data (replace path with your own)
data <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx")
# Filter based on combined conditions
filtered_data <- data %>%
  filter(
    (Index %in% c("BI", "NDSI") & Statistic == Statistic) |
    (Index %in% c("ACItf", "ACIft", "NP", "Hf", "H") &
     Frequency_Range == "R0-24" & Statistic == "mean")
  ) %>%
  mutate(
    Subsample_Color = case_when(
      Subsample == "SLIC" ~ "SLIC",
      Subsample == "halfbasins" ~ "HalfBasins",
      Subsample == "basins" ~ "Basins",
      Subsample == "Landcover" ~ "Landcover",
      TRUE ~ "Random"
    )
  )
# Add synthetic category "ALL"
data_all <- filtered_data %>%
  mutate(Locality = "ALL")
# Merge both datasets
complete_data <- bind_rows(filtered_data, data_all)
# Create plot
plot <- ggplot(complete_data, aes(x = Sample_percent, y = Pearson_Correlation)) +
  geom_point(data = filter(complete_data, Subsample_Color == "Random"),
             aes(color = Subsample_Color),
             alpha = 0.25, size = 1) +
  geom_smooth(method = "lm", color = "blue", se = FALSE, linewidth = 0.8) + 
  geom_point(data = filter(complete_data, Subsample_Color != "Random"),
             aes(color = Subsample_Color), size = 2) +
  scale_color_manual(
    values = c(
      "SLIC" = "purple",
      "HalfBasins" = "skyblue",
      "Basins" = "navy",
      "Random" = "gray50",
      "Landcover" = "green"
    )
  ) +
  facet_grid(Locality ~ Index) +
  theme_minimal(base_size = 12) +
  labs(
    x = "Sample percent",
    y = "Subsample_performance",
    color = "Sampling method"
  ) +
  theme(
    legend.position = "right",
    axis.text = element_text(size = 10),
    strip.text = element_text(size = 12, face = "bold")
  )
# Save as PDF (set your desired path)
ggsave(
  filename = "#/0_Subsampleperformance_vs_SamplePercent_mean.pdf",
  plot = plot,
  width = 15.27,
  height = 8.15,
  units = "in"
)

print(plot)

OBJECTIVE 1 SIZE DEPENDANCE

S. objective 1 - Analyze the relationship between sample size and the spatial representativeness of interpolated soundscapes using different sampling strategies in heterogeneous landscapes;

1.1. Generate the pearson correlation between Sampling percent and design precision.

To evaluate how sampling size influences the performance of each subsampling strategy, we calculated a second Pearson correlation coefficient, Pcoef2. This coefficient quantifies the correlation between the proportion of sampled data (i.e., Sample_percent) and the subsampling performance, previously calculated as Pcoef1 (Pearson correlation between full-sample and subsampled raster surfaces).

The analysis was performed across all combinations of localities, subsampling designs, frequency ranges, time periods, acoustic indices, and summary statistics (e.g., mean, median). For each unique combination, we filtered the data and applied ggscatterstats() from the ggstatsplot package to compute the Pearson correlation (Pcoef2), along with associated test statistics.

The resulting outputs were consolidated into a dataset named DF2, which was later used for statistical comparisons between strategies and visualized using violin and density plots.

Used filters: | Locality | Type | Frequency_Range | Time_Period | Statistic | Index | Pearson_Correlation |

Resulting table will be named “DF2”, which includes the calculated Pcoef2.

# Load required libraries
library(ggstatsplot)
library(dplyr)
library(readxl)
library(openxlsx)
library(future.apply)

# Set up parallel plan
plan(multisession, workers = parallel::detectCores() - 1)

# Load data (replace with appropriate file path)
data <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx") %>%
  mutate(across(c(Locality, Type, Subsample, Frequency_Range, Time_Period, Statistic, Index), as.character))

# Create duplicate with Locality = "ALL"
data_all <- data %>% mutate(Locality = "ALL")
expanded_data <- bind_rows(data, data_all)

# Get unique combinations of filters
combinations <- expanded_data %>%
  distinct(Locality, Type, Frequency_Range, Time_Period, Statistic, Index, Subsample)

# Function to process each combination
process_combination <- function(filter_row) {
  filtered_data <- expanded_data %>%
    filter(
      Locality == filter_row$Locality,
      Type == filter_row$Type,
      Frequency_Range == filter_row$Frequency_Range,
      Time_Period == filter_row$Time_Period,
      Statistic == filter_row$Statistic,
      Index == filter_row$Index,
      Subsample == filter_row$Subsample
    )

  # Check for sufficient data and variation
  if (nrow(filtered_data) < 3 ||
      length(unique(filtered_data$Sample_percent)) < 2 ||
      length(unique(filtered_data$Subsample_performance)) < 2) return(NULL)

  # Extract correlation statistics
  temp_plot <- tryCatch({
    ggscatterstats(
      data = filtered_data,
      x = Sample_percent,
      y = Subsample_performance,
      messages = FALSE
    )
  }, error = function(e) return(NULL))

  if (is.null(temp_plot)) return(NULL)

  stats <- tryCatch(extract_stats(temp_plot), error = function(e) return(NULL))
  if (is.null(stats)) return(NULL)

  subtitle_data <- stats$subtitle_data
  caption_data <- stats$caption_data

  # Add filtering context to results
  for (col in names(filter_row)) {
    subtitle_data[[col]] <- filter_row[[col]]
    caption_data[[col]] <- filter_row[[col]]
  }

  subtitle_data$Type <- "Frequentist"
  caption_data$Type <- "Bayesian"

  bind_rows(subtitle_data, caption_data)
}

# Apply processing to all combinations in parallel
results_list <- future_lapply(1:nrow(combinations), function(i) {
  filter_row <- combinations[i, ]
  process_combination(filter_row)
}, future.seed = TRUE)

# Combine results
final_table <- bind_rows(results_list)

# Remove columns incompatible with Excel
final_table_clean <- final_table %>%
  select_if(~ !any(class(.) %in% c("list", "language")))

# Export final result
write.xlsx(final_table_clean, "DF2_SampleSize_vs_Subsample_performance_Correlations(Pcoeff2).xlsx")

1.2. Visual inspection of sampling size effects

To explore the relationship between sample size and subsampling performance across different categorical variables (e.g., locality, index, strategy), we created an interactive visualization tool using a Shiny application. This tool allows the dynamic generation of violin plots showing the distribution of Pcoef2 values (correlation between sample size and subsample performance) across user-defined categories.

The application permits filtering by multiple metadata fields (e.g., frequency range, time period, statistic, or acoustic index) and dynamically updates the visualization accordingly. Violin plots were generated using the ggplot2 package, with optional overlay of jittered data points. Users can export the resulting plots as PDFs for reporting or supplementary use.

This tool is based on the table DF2, and facilitates visual comparison of the influence of sample size across grouping levels in the dataset.

This visual inspection is only for ALL dataset.

library(shiny)
library(ggplot2)
library(readxl)
library(dplyr)

ui <- fluidPage(
  titlePanel("Distribution of Pearson Coefficient (Frequentist)"),

  sidebarLayout(
    sidebarPanel(
      fileInput("archivo", "Upload Excel file", accept = c(".xlsx")),

      selectInput("variable_categorica", "Categorical variable to compare:",
                  choices = c("Locality", "Frequency_Range", "Time_Period", "Statistic", "Index", "Subsample", "Type")),

      numericInput("axis_title_size", "Axis title font size:", value = 14, min = 8, max = 30),
      numericInput("axis_text_size", "Axis text font size:", value = 12, min = 6, max = 30),

      downloadButton("descargar_pdf", "Download plot as PDF"),

      uiOutput("filtros_adicionales")
    ),

    mainPanel(
      plotOutput("grafico_violin", height = "600px"),
      tableOutput("tabla_filtrada")
    )
  )
)

server <- function(input, output, session) {

  # Read uploaded file
  datos <- reactive({
    req(input$archivo)
    read_excel(input$archivo$datapath) %>%
      filter(Tipo == "Frequentist") %>%
      filter(!is.na(estimate))
  })

  # Dynamic additional filters
  output$filtros_adicionales <- renderUI({
    req(datos())
    other_columns <- setdiff(c("Locality", "Frequency_Range", "Time_Period", "Statistic", "Index", "Subsample", "Type"), input$variable_categorica)

    lapply(other_columns, function(col) {
      selectInput(
        inputId = paste0("filtro_", col),
        label = col,
        choices = c("All", unique(datos()[[col]])),
        selected = "All"
      )
    })
  })

  # Filter data based on selected inputs
  datos_filtrados <- reactive({
    req(datos())
    df <- datos()
    other_columns <- setdiff(c("Locality", "Frequency_Range", "Time_Period", "Statistic", "Index", "Subsample", "Type"), input$variable_categorica)

    for (col in other_columns) {
      val <- input[[paste0("filtro_", col)]]
      if (!is.null(val) && val != "All") {
        df <- df %>% filter(.data[[col]] == val)
      }
    }

    df
  })

  # Generate violin plot
  plot_violines <- reactive({
    df <- datos_filtrados()
    req(nrow(df) > 0)

    ggplot(df, aes(x = .data[[input$variable_categorica]], y = estimate)) +
      geom_violin(fill = "skyblue", alpha = 0.7, color = NA) +
      # geom_jitter(width = 0.15, alpha = 0.5, size = 1.5, color = "black") +
      labs(x = input$variable_categorica, y = "Pearson Estimate") +
      theme_minimal() +
      theme(
        axis.title = element_text(size = input$axis_title_size),
        axis.text = element_text(size = input$axis_text_size),
        plot.title = element_blank()
      )
  })

  output$grafico_violin <- renderPlot({
    plot_violines()
  })

  # Show filtered table
  output$tabla_filtrada <- renderTable({
    datos_filtrados()
  })

  # Download button
  output$descargar_pdf <- downloadHandler(
    filename = function() {
      paste0("violin_plot_pearson_", Sys.Date(), ".pdf")
    },
    content = function(file) {
      ggsave(file, plot = plot_violines(), device = "pdf", width = 10, height = 6)
    }
  )
}

shinyApp(ui = ui, server = server)

1.3. Normality assessment

Before a statistical test to evaluate the size dependance, normality must be checked. To determine whether parametric tests could be applied to compare the sampling strategies, we evaluated the distribution of Pcoef2 values (i.e., correlations between sampling proportion and subsample performance) across all sampling designs. We applied the Shapiro–Wilk test for normality within each subsample category using the rstatix package. Additionally, we visually inspected the distributions by plotting histograms with density curves, faceted by subsample strategy (e.g., basins, SLIC, ssample40).

Results from the Shapiro–Wilk tests and visual assessments revealed widespread deviations from normality, justifying the use of non-parametric statistical tests in subsequent analyses. All results were saved as part of the reproducible workflow, including the test results and distribution plots.

The input is DF2_SampleSize_vs_Subsample_performance_Correlations(Pcoeff2).xlsx. Procedure must be done for mean and median

# Load required packages
library(readxl)
library(dplyr)
library(ggplot2)
library(rstatix)   # for normality tests and summaries
library(ggpubr)    # for visualization

# Load dataset (replace with correct file path)
data <- read_excel("#/DF2_SampleSize_vs_Subsample_performance_Correlations(Pcoeff2).xlsx")
# Filter only Frequentist analyses, remove NA, and keep Statistic == "mean"
data_frec <- data %>%
  filter(
    Tipo == "Frequentist",
    !is.na(estimate),
    Statistic == "mean"   # Change here if you want to use "median", etc.
  )


# Perform Shapiro-Wilk normality test by Subsample
normality <- data_frec %>%
  group_by(Subsample) %>%
  shapiro_test(estimate)

print("### Shapiro-Wilk normality test by Subsample:")
print(normality)

# Create histogram and density plots

plot <- ggplot(data_frec, aes(x = estimate, fill = Subsample)) +
  geom_histogram(aes(y = ..density..), position = "identity", alpha = 0.5, bins = 30) +
  geom_density(alpha = 0.7) +
  facet_wrap(~Subsample) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position = "right",
    axis.text = element_text(size = 10),
    strip.text = element_text(size = 12, face = "bold")
  ) +
  labs(title = NULL, x = "Pearson Estimate", y = "Density")

# Save plot to PDF (update file path)
ggsave(
  filename = "#/R1-3_mean_Distribution_Estimates.pdf",
  plot = plot,
  width = 15.27,
  height = 8.15,
  units = "in"
)

# Display plot
plot

# Export normality test results
library(writexl)
write_xlsx(normality, "#/R1-3_mean_Shapiro_Normality_Test.xlsx")

1.4. Dependence of subsampling strategies on sample size

To evaluate whether different subsampling strategies exhibit distinct levels of sensitivity to sample size, we compared the strength of the correlation (Pcoef2) between sample size (Sample_percent) and subsampling performance across strategies.

We first filtered DF2 to include only frequentist estimates where the Pearson correlation was computed between sample size and design performance (parameter1 == Sample_percent and parameter2 == Pearson_Correlation) using the mean statistic.

Sampling strategies were then grouped into two categories: "random" (e.g., ssample*) and "tessellation" (e.g., grid-based designs such as SLIC or basins). For each group, we summarized the distribution of Pcoef2 values through descriptive statistics (mean, median, SD, IQR, CV).

Given the lack of normality (as previously assessed), we employed a non-parametric Wilcoxon rank-sum test to compare Pcoef2 distributions between the two strategy types.

Due to the lack of normality, a Wilcoxon rank-sum test was used to compare the distributions of Pcoef2 between groups. We also applied a Fligner–Killeen test to evaluate differences in dispersion between strategies.

All results were visualized using violin and boxplots. Summary tables and test outputs were exported for reproducibility.

# Load required libraries
library(readxl)
library(dplyr)
library(psych)
library(writexl)
library(ggplot2)

# Load results table DF2 (adjust path)
data <- read_excel("#/DF2_SampleSize_vs_Subsample_performance_Correlations(Pcoeff2).xlsx")

# Filter valid Pearson correlations between Sample_percent and Pearson_Correlation (Frequentist, Statistic = "median")
data_frec <- data %>%
  filter(
    parameter1 == "Sample_percent",
    parameter2 == "Subsample_performance",
    effectsize == "Pearson correlation",
    Tipo == "Frequentist",
    Statistic == "median",
    !is.na(estimate)
  )

# Classify sampling strategy
data_frec <- data_frec %>%
  mutate(Type_group = case_when(
    grepl("^ssample", Subsample) ~ "random",
    TRUE ~ "tessellation"
  ))

# Descriptive statistics for Pcoef2 by strategy group
summary_dependency <- data_frec %>%
  group_by(Type_group) %>%
  summarise(
    n = n(),
    mean_Pcoef2 = mean(estimate, na.rm = TRUE),
    median_Pcoef2 = median(estimate, na.rm = TRUE),
    sd_Pcoef2 = sd(estimate, na.rm = TRUE),
    iqr_Pcoef2 = IQR(estimate, na.rm = TRUE),
    cv_Pcoef2 = sd(estimate, na.rm = TRUE) / abs(mean(estimate, na.rm = TRUE))
  )

print("Summary of sample size dependency by strategy group:")
print(summary_dependency)

# Wilcoxon rank-sum test
wilcox <- wilcox.test(estimate ~ Type_group, data = data_frec)
print("Wilcoxon test between random and tessellation strategies:")
print(wilcox)

# Fisher's Z comparison of correlation strength

random <- data_frec %>% filter(Type_group == "random")
tess <- data_frec %>% filter(Type_group == "tessellation")

fisherz <- r.test(
  n = nrow(random), r12 = cor(random$`Sample percent`, random$estimate),
  n2 = nrow(tess), r34 = cor(tess$`Sample percent`, tess$estimate)
)

print("Fisher's Z test for correlation strength:")
print(fisherz)
# Fligner–Killeen test for dispersion differences
fligner <- fligner.test(estimate ~ Type_group, data = data_frec)
print("Fligner–Killeen test for variance differences:")
print(fligner)

# Optional plot: distribution of Pcoef2 values
ggplot(data_frec, aes(x = Type_group, y = estimate, fill = Type_group)) +
  geom_violin(alpha = 0.5) +
  geom_boxplot(width = 0.2, outlier.shape = NA, alpha = 0.8) +
  labs(title = "Sample size dependence (Pcoef2)", y = "Pcoef2 (correlation)", x = "Sampling strategy") +
  theme_minimal(base_size = 14) +
  scale_y_continuous(limits = c(-1, 1), oob = scales::squish)

# Export values and summaries
write_xlsx(
  list(
    Pcoef2_Values = data_frec,
    Group_Summary = summary_dependency
  ),
  path = "#/R1-4_MEDIAN_SAMPLING_STRATEGY_COMPARISON.xlsx"
)
# Export F-test results (MEDIAN)

write_xlsx(
  list(
    Pcoef2_Spread_Summary = summary_dependency,
    F_Test_Variance = as.data.frame(t(c(
      F_statistic = 0.79566,
      df1 = 167,
      df2 = 152,
      p_value = 0.149,
      CI_lower = 0.5818262,
      CI_upper = 1.0855697
    )))
  ),
  path = "#/R1-4_MEDIAN_Pcoef2_VARIANCE_TEST.xlsx"
)

# Export F-test results (MEAN)
write_xlsx(
  list(
    Pcoef2_Spread_Summary = summary_dependency,
    F_Test_Variance = as.data.frame(t(c(
      F_statistic = 0.70577,
      df1 = 167,
      df2 = 163,
      p_value = 0.02567,
      CI_lower = 0.5194396,
      CI_upper = 0.9583777
    )))
  ),
  path = "#/R1-4_MEAN_Pcoef2_VARIANCE_TEST.xlsx"
)

# Save final plot as PDF
final_plot <- ggplot(data_frec, aes(x = Type_group, y = estimate, fill = Type_group)) +
  geom_violin(alpha = 0.5, trim = FALSE) +
  geom_boxplot(width = 0.2, outlier.shape = NA, alpha = 0.8) +
  scale_fill_manual(values = c("random" = "#F8766D", "tessellation" = "#00BFC4")) +
  labs(title = "Sample size dependency (Pcoef2)",
       y = "Pcoef2 (correlation)",
       x = "Sampling strategy") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none") +
  coord_cartesian(ylim = c(-1, 1)) +
  scale_y_continuous(limits = c(-1, 1), oob = scales::squish)

ggsave(
  filename = "#/R1-4_MEDIAN_Pcoef2_SAMPLING_STRATEGY.pdf",
  plot = final_plot,
  width = 8,
  height = 6,
  units = "in"
)

OBJECTIVE 2: EXPLORE EFFECTIVENESS OF STRATIFIED SAMPLING DESIGNS

Compare the performance of different sampling strategies, including random and stratified approaches, genarated by segmentation methods.

To assess the effectiveness of tessellation-based sampling strategies, we conducted a multi-step statistical analysis using R. First, we calculated two metrics for each subsample: (1) subsample performance in the form of Pearson correlation between the subsample and its full reference dataset; and (2) sampling efficiency, computed as the ratio between Pearson correlation and the sampling effort (Subsample performance/Sample_percent).

We then grouped data by summary statistic type (mean or median) and computed descriptive statistics for each tessellation strategy, including sample size, central tendency (mean, median), dispersion (standard deviation), and coefficient of variation.

Normality of Pearson correlations was assessed using the Shapiro–Wilk test within each subsampling group, using shapiro_test() from the rstatix package.

Given widespread non-normality, we applied Kruskal–Wallis rank-sum tests to compare both raw performance and efficiency across subsampling strategies. Where differences were detected, we used Dunn’s post-hoc tests with Benjamini–Hochberg correction to evaluate pairwise contrasts.

Violin and boxplots were generated to visually compare the distribution of both performance and efficiency across subsampling methods. All procedures were run separately for mean and median statistics, and results (summary tables and plots) were exported to PDF and Excel formats.

Packages we used: dplyr, ggplot2, ggpubr, rstatix, FSA, writexl.

The entry database is: DF1-1_Interpolations_variograms_and error_for_subsamples.xlsx

# Load required libraries
library(dplyr)
library(ggplot2)
library(readxl)
library(ggpubr)
library(rstatix)
library(FSA)
library(writexl)

# Load data (replace path accordingly)
df <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx") %>%
  mutate(across(c(Subsample, Type, Index, Statistic), as.character)) %>%
  mutate(Pearson_rel = Pearson_Correlation / Sample_percent)

# Loop through each summary statistic type
for (stat in c("mean", "median")) {
  
  df_tess <- df %>%
    filter(Type == "Tessells", Statistic == stat, !is.na(Pearson_Correlation))
  
  # Summary statistics of precision and efficiency
  summary_precision <- df_tess %>%
    group_by(Subsample) %>%
    summarise(
      n = n(),
      mean_Pearson = mean(Pearson_Correlation, na.rm = TRUE),
      median_Pearson = median(Pearson_Correlation, na.rm = TRUE),
      sd_Pearson = sd(Pearson_Correlation, na.rm = TRUE),
      mean_eff = mean(Pearson_rel, na.rm = TRUE),
      median_eff = median(Pearson_rel, na.rm = TRUE),
      sd_eff = sd(Pearson_rel, na.rm = TRUE),
      cv_eff = sd_eff / abs(mean_eff)
    ) %>%
    arrange(desc(median_eff))
  
  # Shapiro-Wilk normality test (only for groups with n >= 3)
  
  valid <- df_tess %>%
    group_by(Subsample) %>%
    summarise(n = n()) %>%
    filter(n >= 3) %>%
    pull(Subsample)
  
  normality_df <- df_tess %>%
    filter(Subsample %in% valid) %>%
    group_by(Subsample) %>%
    shapiro_test(Pearson_Correlation)

  
  # Precision plot
  precision_plot <- ggplot(df_tess, aes(x = Subsample, y = Pearson_Correlation, fill = Subsample)) +
    geom_violin(trim = FALSE) +
    geom_boxplot(width = 0.2, outlier.shape = NA) +
    theme_minimal() +
    labs(title = paste("Strategy precision (Pearson) -", stat), y = "Pearson Correlation") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    scale_y_continuous(limits = c(-1, 1), oob = scales::squish)

  ggsave(
    paste0("#/Tessellation_KW_Precision_", stat, ".pdf"),
    plot = precision_plot,
    width = 8, height = 6, units = "in"
  )
  
  # Efficiency plot:
  
  efficiency_plot <- ggplot(df_tess, aes(x = Subsample, y = Pearson_rel, fill = Subsample)) +
    geom_violin(trim = FALSE) +
    geom_boxplot(width = 0.2, outlier.shape = NA) +
    theme_minimal() +
    labs(title = paste("Strategy efficiency (Pearson / Sample%) -", stat), y = "Relative Pearson") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

  ggsave(
    paste0("#/Tessellation_KW_Efficiency_", stat, ".pdf"),
    plot = efficiency_plot,
    width = 8, height = 6, units = "in"
  )

  # Kruskal–Wallis tests and post-hoc comparisions:
  kw_pearson <- kruskal_test(Pearson_Correlation ~ Subsample, data = df_tess)
  posthoc_pearson <- dunn_test(Pearson_Correlation ~ Subsample, data = df_tess, p.adjust.method = "BH")
  
  kw_eff <- kruskal_test(Pearson_rel ~ Subsample, data = df_tess)
  posthoc_eff <- dunn_test(Pearson_rel ~ Subsample, data = df_tess, p.adjust.method = "BH")
  
  # Export results to Excel
  write_xlsx(
    list(
      Summary_Statistics = summary_precision,
      Normality_Test = normality_df,
      KW_Pearson = as.data.frame(kw_pearson),
      PostHoc_Pearson = as.data.frame(posthoc_pearson),
      KW_Efficiency = as.data.frame(kw_eff),
      PostHoc_Efficiency = as.data.frame(posthoc_eff)
    ),
    path = paste0("#/KW_Tessellation_Strategies_", stat, ".xlsx")
  )
}

OBJECTIVE 3:

Specific objective 3: To explore how the interplay of categorical (e.g., landscape, time, index) and continuous variables (e.g., sample size, performance) explains the multivariate structure that differentiates stratified subsampling strategies.

3.1 FAMD analyses

A Factorial Analysis of Mixed Data (FAMD) is conducted to explore the multivariate structure of stratified subsampling strategies by integrating both categorical and continuous variables. The dataset was filtered to retain only relevant observations (e.g., median statistics from tessellation-based designs) and included key landscape, temporal, acoustic, and performance variables. The variable Subsample, which defines the sampling strategy under evaluation, was treated as a supplementary qualitative variable to avoid influencing the dimensional construction.

FAMD was performed using the FactoMineR package, extracting the coordinates of individuals, the contributions of quantitative and qualitative variables, and the proportion of variance explained by each dimension. Results were organized into separate Excel sheets for subsequent visualization and statistical analysis.

library(readxl)
library(FactoMineR)
library(factoextra)
library(dplyr)
library(openxlsx)

# Load dataset (replace path as needed)
data <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx")

# Filter only valid values and select relevant columns
data_famd <- data %>%
  filter(!is.na(Pearson_Correlation), Statistic == "median", Type == "Tessells") %>%
  select(Locality, Frequency_Range, Time_Period, Index, Subsample, Sample_percent, Pearson_Correlation)

# Convert categorical variables to factors
data_famd <- data_famd %>%
  mutate(across(c(Locality, Frequency_Range, Time_Period, Index, Subsample), as.factor))

# Identify the supplementary qualitative variable (Subsample)
supplementary_var_index <- which(colnames(data_famd) == "Subsample")

# Run FAMD with Subsample as a supplementary variable
famd_result <- FAMD(data_famd, 
                    ncp = 5, 
                    sup.var = supplementary_var_index,
                    graph = FALSE)

# Extract coordinates of individuals and variables
coord_ind <- as.data.frame(famd_result$ind$coord)
coord_ind$ID <- rownames(coord_ind)

coord_quanti <- as.data.frame(famd_result$quanti.var$coord)
coord_quanti$Variable <- rownames(coord_quanti)

coord_quali <- as.data.frame(famd_result$quali.var$coord)
coord_quali$Category <- rownames(coord_quali)

eig <- as.data.frame(famd_result$eig)
colnames(eig) <- c("Dimension", "Variance (%)", "Cumulative Variance (%)")

# Save results to Excel
wb <- createWorkbook()
addWorksheet(wb, "Individual_Coordinates")
addWorksheet(wb, "Quantitative_Variables")
addWorksheet(wb, "Qualitative_Variables")
addWorksheet(wb, "Explained_Variance")

writeData(wb, sheet = "Individual_Coordinates", coord_ind)
writeData(wb, sheet = "Quantitative_Variables", coord_quanti)
writeData(wb, sheet = "Qualitative_Variables", coord_quali)
writeData(wb, sheet = "Explained_Variance", eig)

saveWorkbook(wb, "#/FAMD_results_export.xlsx", overwrite = TRUE)

3.2 Graphical abstract plots for FAMD

This script generates a visual summary of the Factorial Analysis of Mixed Data (FAMD) results. It includes a scree plot showing the variance explained by each dimension, along with bar plots displaying the top contributing variables to Dimensions 1 through 4. All plots are styled consistently using a minimal theme and arranged using the patchwork package into a single combined figure. The final output is saved as a high-resolution PDF for publication or reporting purposes.

# Load required libraries
# Ensure 'patchwork' is installed: install.packages("patchwork")
library(factoextra)
library(patchwork)   # For combining ggplot-based charts
library(ggplot2)

# Assumes 'famd_result' already exists and is valid
# (This is the result object from our prevously constructed FAMD analysis)
# Create and customize individual plots
# Scree plot with theme and y-axis view adjustment
plot_scree <- fviz_screeplot(famd_result, addlabels = TRUE, 
                             ggtheme = theme_minimal()) +
  ggtitle("Scree Plot (Explained Variance by Dimension)") +
  coord_cartesian(ylim = c(0, 17))  # Adjust this upper limit if needed

# Contribution plots for dimensions 1 to 4
plot_contrib_dim1 <- fviz_contrib(famd_result, choice = "var", axes = 1, top = 10,
                                  ggtheme = theme_minimal()) +
  ggtitle("Contribution to Dim.1 (Top 10)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot_contrib_dim2 <- fviz_contrib(famd_result, choice = "var", axes = 2, top = 10,
                                  ggtheme = theme_minimal()) +
  ggtitle("Contribution to Dim.2 (Top 10)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot_contrib_dim3 <- fviz_contrib(famd_result, choice = "var", axes = 3, top = 10,
                                  ggtheme = theme_minimal()) +
  ggtitle("Contribution to Dim.3 (Top 10)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot_contrib_dim4 <- fviz_contrib(famd_result, choice = "var", axes = 4, top = 10,
                                  ggtheme = theme_minimal()) +
  ggtitle("Contribution to Dim.4 (Top 10)") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Combine plots using patchwork
combined_plot <- plot_scree /
  (plot_contrib_dim1 + plot_contrib_dim2) /
  (plot_contrib_dim3 + plot_contrib_dim4)

# Add global title to the full layout
combined_plot <- combined_plot + 
  plot_annotation(title = "      FAMD - MEDIAN")

# Display combined plot
print(combined_plot)

# Save the combined plot as PDF (update path accordingly)
ggsave(
  filename = "#/FAMD_summary_plot_MEDIAN.pdf",
  plot = combined_plot,
  device = "pdf",
  width = 8,
  height = 10,
  units = "in"
)

3.3 Variables projection and individuals plot

# Load required libraries
library(readxl)
library(FactoMineR)
library(factoextra)
library(dplyr)
library(ggplot2)
library(patchwork)

# Load dataset (adjust path accordingly)
data <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx")

# Prepare variables for FAMD
data_famd <- data %>%
  filter(!is.na(Pearson_Correlation), Statistic == "median", Type == "Tessells") %>%
  select(Locality, Frequency_Range, Time_Period, Index, Subsample, Sample_percent, Pearson_Correlation) %>%
  mutate(across(c(Locality, Frequency_Range, Time_Period, Index, Subsample), as.factor))

# Run FAMD (Factorial Analysis of Mixed Data)
famd_result <- FAMD(data_famd, ncp = 5, graph = FALSE)

# Variable projection plots (repel = TRUE for label clarity)
plot_var_12 <- fviz_famd_var(famd_result, axes = c(1, 2), repel = TRUE) + 
  ggtitle("Variables: Dim 1 vs Dim 2")
plot_var_23 <- fviz_famd_var(famd_result, axes = c(2, 3), repel = TRUE) + 
  ggtitle("Variables: Dim 2 vs Dim 3")
plot_var_13 <- fviz_famd_var(famd_result, axes = c(1, 3), repel = TRUE) + 
  ggtitle("Variables: Dim 1 vs Dim 3")
# Individual projection plots (clean version without labels, with ellipses by Subsample)
plot_ind_12 <- fviz_famd_ind(famd_result, axes = c(1, 2), habillage = "Subsample", 
                             addEllipses = TRUE, label = "none") + 
  ggtitle("Individuals: Dim 1 vs Dim 2")
plot_ind_23 <- fviz_famd_ind(famd_result, axes = c(2, 3), habillage = "Subsample", 
                             addEllipses = TRUE, label = "none") + 
  ggtitle("Individuals: Dim 2 vs Dim 3")
plot_ind_13 <- fviz_famd_ind(famd_result, axes = c(1, 3), habillage = "Subsample", 
                             addEllipses = TRUE, label = "none") + 
  ggtitle("Individuals: Dim 1 vs Dim 3")

# Combine all plots in a 2-column × 3-row layout
combined_plot <- (plot_var_12 | plot_ind_12) /
                 (plot_var_23 | plot_ind_23) /
                 (plot_var_13 | plot_ind_13) +
                 plot_annotation(title = "FAMD Projections – Variables & Individuals",
                                 theme = theme(plot.title = element_text(size = 16, face = "bold")))
# Display the combined plot
print(combined_plot)

# Save the plot to PDF (update path as needed)
ggsave(
  filename = "#/FAMD_variables_individuals_clean_MEDIAN.pdf",
  plot = combined_plot,
  device = "pdf",
  width = 12,
  height = 14,
  units = "in"
)

3.4 KRUSKALL TEST

This graph presents the results of a statistical analysis (Kruskal-Wallis + post-hoc Dunn) applied to the coordinates of dimension 3 (Dim.3) of the FAMD analysis, with the aim of comparing the stratified sampling methods (Subsample: basins, halfbasins, SLIC).

# Load required libraries
library(readxl)
library(FactoMineR)
library(factoextra)
library(dplyr)
library(rstatix)
library(ggpubr)
library(multcompView)
library(tibble)
library(tidyr)
library(ggplot2)
library(patchwork)
library(writexl)

# Load and prepare data
data <- read_excel("#/DF1-1_Interpolations_variograms_and_error_for_subsamples.xlsx")

data_famd <- data %>%
  filter(!is.na(Pearson_Correlation), Statistic == "median", Type == "Tessells") %>%
  select(Locality, Frequency_Range, Time_Period, Index, Subsample, Sample_percent, Pearson_Correlation) %>%
  mutate(across(c(Locality, Frequency_Range, Time_Period, Index, Subsample), as.factor))

# Run FAMD
famd_result <- FAMD(data_famd, ncp = 5, graph = FALSE)

ind_coord <- as.data.frame(famd_result$ind$coord[, 1:4])  # Keep only first four dimensions
ind_coord$Subsample <- data_famd$Subsample

# Define a reusable function for each dimension's analysis
kruskal_dunn_plot <- function(df, dim_num) {
  dim_col <- paste0("Dim.", dim_num)
  
  kw <- kruskal_test(as.formula(paste0(dim_col, " ~ Subsample")), data = df)
  dunn <- dunn_test(as.formula(paste0(dim_col, " ~ Subsample")), data = df, p.adjust.method = "BH")

  letters_df <- NULL
  if (kw$p < 0.05) {
    groups <- levels(df$Subsample)
    pmat <- matrix(1, length(groups), length(groups), dimnames = list(groups, groups))
    diag(pmat) <- 0
    for (i in 1:nrow(dunn)) {
      pmat[dunn$group1[i], dunn$group2[i]] <- dunn$p.adj[i]
      pmat[dunn$group2[i], dunn$group1[i]] <- dunn$p.adj[i]
    }
    signif_matrix <- pmat < 0.05
    diag(signif_matrix) <- FALSE
    letters <- multcompLetters(signif_matrix)$Letters
    letters_df <- enframe(letters, name = "Subsample", value = "Letter")
    
    pos <- df %>%
      group_by(Subsample) %>%
      summarise(
        q3 = quantile(.data[[dim_col]], 0.75),
        iqr = IQR(.data[[dim_col]]),
        upper = q3 + 1.5 * iqr,
        max = max(.data[[dim_col]], na.rm = TRUE),
        y.position = max(upper, max) + 0.15
      )
    
    letters_df <- left_join(letters_df, pos, by = "Subsample")
  }

  ymax <- max(df[[dim_col]], na.rm = TRUE)
  bracket_y <- if (!is.null(letters_df)) max(letters_df$y.position, na.rm = TRUE) + 0.1 else ymax + 0.2

  dunn_plot <- dunn %>%
    filter(p.adj <= 0.05) %>%
    arrange(group1, group2) %>%
    mutate(y.position = seq(bracket_y, by = 0.15, length.out = n()))

  plot <- ggboxplot(df, x = "Subsample", y = dim_col, fill = "Subsample", palette = "Set2") +
    labs(
      title = paste("Kruskal-Wallis by Subsampling Strategy - Dimension", dim_num),
      subtitle = get_test_label(kw, detailed = TRUE),
      y = paste("FAMD Coordinate - Dim", dim_num),
      x = "Subsampling Strategy"
    ) +
    theme_minimal(base_size = 14) +
    theme(legend.position = "none")

  if (!is.null(letters_df)) {
    plot <- plot + geom_text(data = letters_df, aes(x = Subsample, y = y.position, label = Letter),
                             inherit.aes = FALSE, size = 5, vjust = -0.5)
  }

  if (nrow(dunn_plot) > 0) {
    plot <- plot + stat_pvalue_manual(dunn_plot, label = "p.adj.signif", tip.length = 0.01)
  } else if (kw$p < 0.05) {
    plot <- plot + labs(caption = "Kruskal-Wallis was significant, but no pairwise differences detected.")
  }

  return(plot)
}

# Generate plots for the first four dimensions
plot_dim1 <- kruskal_dunn_plot(ind_coord, 1)
plot_dim2 <- kruskal_dunn_plot(ind_coord, 2)
plot_dim3 <- kruskal_dunn_plot(ind_coord, 3)
plot_dim4 <- kruskal_dunn_plot(ind_coord, 4)

# Combine all plots into a grid layout
final_plot <- (plot_dim1 | plot_dim2) / (plot_dim3 | plot_dim4) +
  plot_annotation(title = "Kruskal–Wallis + Dunn Tests – FAMD Dimensions")

# Save final plot to PDF
ggsave(
  filename = "#/FAMD_KW_Dunn_Results.pdf",
  plot = final_plot,
  device = "pdf",
  width = 14,
  height = 12,
  units = "in"
)

# Export results for each dimension to Excel
library(openxlsx)

wb <- createWorkbook()

for (dim_num in 1:4) {
  dim_col <- paste0("Dim.", dim_num)

  kw_result <- kruskal_test(as.formula(paste0(dim_col, " ~ Subsample")), data = ind_coord)
  dunn_result <- dunn_test(as.formula(paste0(dim_col, " ~ Subsample")), data = ind_coord, p.adjust.method = "BH")

  groups <- levels(ind_coord$Subsample)
  pmat <- matrix(1, length(groups), length(groups), dimnames = list(groups, groups))
  diag(pmat) <- 0

  for (i in 1:nrow(dunn_result)) {
    pmat[dunn_result$group1[i], dunn_result$group2[i]] <- dunn_result$p.adj[i]
    pmat[dunn_result$group2[i], dunn_result$group1[i]] <- dunn_result$p.adj[i]
  }

  signif_matrix <- pmat < 0.05
  diag(signif_matrix) <- FALSE
  letters <- multcompLetters(signif_matrix)$Letters
  letters_df <- enframe(letters, name = "Subsample", value = "Significance_Letter")

  sheet_name <- paste0("Dimension_", dim_num)
  if (sheet_name %in% names(wb)) removeWorksheet(wb, sheet = sheet_name)

  addWorksheet(wb, sheet_name)
  writeData(wb, sheet = sheet_name, x = kw_result, startCol = 1, startRow = 1)
  writeData(wb, sheet = sheet_name, x = dunn_result, startCol = 1, startRow = 5)
  writeData(wb, sheet = sheet_name, x = letters_df, startCol = 1, startRow = nrow(dunn_result) + 8)
}

saveWorkbook(wb, file = "#/FAMD_KW_Dunn_results_export.xlsx", overwrite = TRUE)

3.5 HEATMAP

library(dplyr)
library(tidyr)
library(ggplot2)
library(ggtext)  # Opcional: para texto enriquecido


letras_df <- tribble(
  ~STATISTIC, ~DIMENSION, ~Subsample, ~Significance_Letter,
  "median","Dim.1", "basins",     "a",
  "median","Dim.1", "halfbasins", "b",
  "median","Dim.1", "Landcover",  "c",
  "median","Dim.1", "SLIC",       "d",
  "median","Dim.2", "basins",     "a",
  "median","Dim.2", "halfbasins", "b",
  "median","Dim.2", "Landcover",  "c",
  "median","Dim.2", "SLIC",       "ab",
  "median","Dim.3", "basins",     "a",
  "median","Dim.3", "halfbasins", "b",
  "median","Dim.3", "Landcover",  "b",
  "median","Dim.3", "SLIC",       "b",
  "median","Dim.4", "basins",     "a",
  "median","Dim.4", "halfbasins", "b",
  "median","Dim.4", "Landcover",  "c",
  "median","Dim.4", "SLIC",       "c"
)

# Pivotear a formato ancho
letras_matrix <- letras_df %>%
  unite("Dimension_Type", STATISTIC, DIMENSION, sep = "_") %>%
  pivot_wider(names_from = Dimension_Type, values_from = Significance_Letter)

# Convertir en data.frame para ggplot
letras_long <- letras_matrix %>%
  pivot_longer(cols = -Subsample, names_to = "Dimension", values_to = "Letter")

# Ordenar para estética
letras_long$Subsample <- factor(letras_long$Subsample, levels = c("basins", "halfbasins", "Landcover", "SLIC"))
letras_long$Dimension <- factor(letras_long$Dimension,
                                levels = c("mean_Dim.1", "mean_Dim.2", "mean_Dim.3", "mean_Dim.4",
                                           "median_Dim.1", "median_Dim.2", "median_Dim.3", "median_Dim.4"))

# Heatmap
ggplot(letras_long, aes(x = Dimension, y = Subsample, fill = Letter)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Letter), size = 5) +
  scale_fill_viridis_d(option = "plasma", direction = -1) +
  labs(
    title = "Significance Letter Groupings by FAMD Dimension and Strategy",
    x = "FAMD Dimension", y = "Subsampling Strategy", fill = "Letter"
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggsave(
  filename = "/home/vmartinezarias/Dropbox/Doctorado_Personal_Folder/ThesisAnalyses/PROVISIONALES_PAPERS/OBJECTIVE3/V2/3.5-FAMD_heatmap_letters.pdf",
  plot = last_plot(),  # o guarda tu plot en un objeto: p <- ggplot(...) y pon plot = p
  width = 10,
  height = 6,
  units = "in",
  device = "pdf"
)

4 OBJECTIVE 4: LANDSCAPE REPRESENTATION

Specific objective 4: Determine the influence of landscape heterogeneity on the performance and representativeness of soundscape information obtained using tessellation-based sampling strategies

library(tidyverse)
library(readxl)
library(ggpubr)
library(openxlsx)  # For exporting to Excel

# Load Excel file
df <- read_excel("#/DF3_Subsampling_Heterogeneity_Comparison.xlsx")

# Filter valid values
df_filtered <- df %>% filter(!is.na(L_proxy_mean))

# Extract unique localities
localities <- unique(df_filtered$Locality)

# Set PDF output path
output_pdf <- "#/Comparative_Plots_Lproxy_mean_POLYPOLES_ALLTOGETHER.pdf"
pdf_opened <- FALSE

# Initialize results table
statistical_results <- data.frame(
  Locality = character(),
  Method = character(),
  Procedence = character(),
  KS_statistic = numeric(),
  KS_p_value = numeric(),
  Wasserstein = numeric(),
  stringsAsFactors = FALSE
)

for (loc in localities) {
  cat("\n\n📍 Locality:", loc, "\n")

  df_loc <- df_filtered %>% filter(Locality == loc)
  full_vals <- df_loc %>% filter(Tessell == "complete") %>% pull(L_proxy_mean)

  for (method in unique(df_loc$Tessell)) {
    if (method == "complete") next

    df_sub_all <- df_loc %>% filter(Tessell == method & Procedence %in% c("Examinated", "Poles"))
    if (nrow(df_sub_all) == 0) next

    # Compute statistics by procedence
    for (proc in c("Examinated", "Poles")) {
      df_sub <- df_loc %>% filter(Tessell == method, Procedence == proc)
      if (nrow(df_sub) == 0) next

      sub_vals <- df_sub$L_proxy_mean
      n <- min(length(full_vals), length(sub_vals))
      ks <- ks.test(full_vals, sub_vals)
      wass <- mean(abs(sort(full_vals)[1:n] - sort(sub_vals)[1:n]))

      cat("🔎 Method:", method, "| Procedence:", proc, "\n")
      cat("   KS p-value:", ks$p.value, "\n")
      cat("   KS statistic:", ks$statistic, "\n")
      cat("   Approx. Wasserstein distance:", round(wass, 4), "\n")

      statistical_results <- rbind(statistical_results, data.frame(
        Locality = loc,
        Method = method,
        Procedence = proc,
        KS_statistic = as.numeric(ks$statistic),
        KS_p_value = as.numeric(ks$p.value),
        Wasserstein = round(wass, 4),
        stringsAsFactors = FALSE
      ))
    }

    # Generate density and Q–Q plots
    if (!pdf_opened) {
      pdf(output_pdf, width = 14, height = 6)
      pdf_opened <- TRUE
    }

    # Density plot
    p1 <- ggplot(
      df_loc %>% filter((Tessell == method & Procedence %in% c("Examinated", "Poles")) | Tessell == "complete"),
      aes(x = L_proxy_mean, fill = interaction(Tessell, Procedence, drop = TRUE))
    ) +
      geom_density(alpha = 0.4) +
      theme_minimal() +
      labs(title = "Density Plot",
           x = "L_proxy_mean", y = "Density", fill = "Tessellation / Procedence")

    # Q–Q plot
    qq_dfs <- list()
    for (proc in c("Examinated", "Poles")) {
      df_sub <- df_loc %>% filter(Tessell == method, Procedence == proc)
      if (nrow(df_sub) == 0) next

      sub_vals <- df_sub$L_proxy_mean
      n <- min(length(full_vals), length(sub_vals))

      qq_dfs[[proc]] <- data.frame(
        complete = sort(full_vals)[1:n],
        sub = sort(sub_vals)[1:n],
        Procedence = proc
      )
    }
    qq_df_all <- bind_rows(qq_dfs)

    p2 <- ggplot(qq_df_all, aes(x = complete, y = sub, color = Procedence)) +
      geom_point(alpha = 0.6) +
      geom_abline(slope = 1, intercept = 0, color = "black", linetype = "dashed") +
      theme_minimal() +
      labs(title = "Q–Q Plot", x = "Complete Distribution", y = method)

    combined <- ggarrange(p2, p1, ncol = 2, widths = c(1, 1),
                          labels = c("A", "B"),
                          common.legend = TRUE, legend = "right")

    combined <- annotate_figure(combined,
                                 top = text_grob(paste0(loc, " / ", method, " / Comparison with Examinated & Poles"),
                                                 face = "bold", size = 14))

    print(combined)
  }
}

if (pdf_opened) {
  dev.off()
  cat("\n✅ PDF successfully generated with all comparisons and statistics.\n")
} else {
  cat("\n⚠️ No plots were generated. Please check available data.\n")
}

# Save statistical results to Excel
output_excel <- "#/Comparative_Stats_Lproxy_mean_POLYPOLES_ALLTOGETHER.xlsx"
write.xlsx(statistical_results, output_excel)
LS0tCnRpdGxlOiAnQXBwZW5kaXggUzk6IENvZGVzIGZvciB1c2VkIHN0YXRpc3RpY2FsIGFuYWx5c2VzJwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAnMicKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAnMicKLS0tCgojIyMgQXBwZW5kaXggUzEwOiBDb2RlcyBmb3IgdXNlZCBzdGF0aXN0aWNhbCBhbmFseXNlcwoKKipUaXRsZToqKiAqQSB3b3JrZmxvdyB0byBvcHRpbWl6ZSBzcGF0aWFsIHNhbXBsaW5nIGluIGVjb2Fjb3VzdGljIHN0dWRpZXMqXAoqKkpvdXJuYWw6KiogKkxhbmRzY2FwZSBFY29sb2d5KgoKKipBdXRob3JzOioqXApNYXJ0w61uZXotQXJpYXMsIFYuIE0uXHRleHRzdXBlcnNjcmlwdHsxfTsgUGFuaWFndWEtVmlsbGFkYSwgQy5cdGV4dHN1cGVyc2NyaXB0ezF9OyBEYXphLCBKLiBNLlx0ZXh0c3VwZXJzY3JpcHR7MX0KCioqQXV0aG9yIGFmZmlsaWF0aW9ucyBhdCB0aGUgdGltZSB0aGUgd29yayB3YXMgY29uZHVjdGVkOioqXAoxLiBHcnVwbyBIZXJwZXRvbMOzZ2ljbyBkZSBBbnRpb3F1aWEsIENhbGxlIDcwIE5vLiA1MiAtIDIxLCBQb3N0YWwgQ29kZSAwNTAwMTAsIE1lZGVsbMOtbiwgQ29sb21iaWEuCgoqKkNvcnJlc3BvbmRpbmcgYXV0aG9yOioqXApWaWN0b3IgTS4gTWFydMOtbmV6LUFyaWFzXArwn5OnIEVtYWlsOiBbdm1hbnVlbC5tYXJ0aW5lelxAdWRlYS5lZHUuY29dKG1haWx0bzp2bWFudWVsLm1hcnRpbmV6QHVkZWEuZWR1LmNvKXsuZW1haWx9XArwn5OeIFRlbDogKzU3IDMxMSA2NzkgNzg0NgoKIyAwLiBFeHBsb3JhdGlvbiBncmFwaGljCgpUaGlzIGdyYXBoaWMgYWxsb3cgdG8gdmlzdWFsbHkgY29tcGFyZSB0aGUgaW5kaWNlcyBpbiB0aGUgcmFuZ2UgMC0yNGtoeiwgZm9yIGFsbCBob3VycyBhbmQgbG9jYWxpdGllcy4gV2UgZGlkIG5vdCB1c2UgaXQKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGRwbHlyKQoKU3RhdGlzdGljIDwtICJtZWFuIiAgIyBTZXQgdG8gIm1lYW4iIG9yICJtZWRpYW4iCiMgTG9hZCBkYXRhIChyZXBsYWNlIHBhdGggd2l0aCB5b3VyIG93bikKZGF0YSA8LSByZWFkX2V4Y2VsKCIjL0RGMS0xX0ludGVycG9sYXRpb25zX3ZhcmlvZ3JhbXNfYW5kX2Vycm9yX2Zvcl9zdWJzYW1wbGVzLnhsc3giKQojIEZpbHRlciBiYXNlZCBvbiBjb21iaW5lZCBjb25kaXRpb25zCmZpbHRlcmVkX2RhdGEgPC0gZGF0YSAlPiUKICBmaWx0ZXIoCiAgICAoSW5kZXggJWluJSBjKCJCSSIsICJORFNJIikgJiBTdGF0aXN0aWMgPT0gU3RhdGlzdGljKSB8CiAgICAoSW5kZXggJWluJSBjKCJBQ0l0ZiIsICJBQ0lmdCIsICJOUCIsICJIZiIsICJIIikgJgogICAgIEZyZXF1ZW5jeV9SYW5nZSA9PSAiUjAtMjQiICYgU3RhdGlzdGljID09ICJtZWFuIikKICApICU+JQogIG11dGF0ZSgKICAgIFN1YnNhbXBsZV9Db2xvciA9IGNhc2Vfd2hlbigKICAgICAgU3Vic2FtcGxlID09ICJTTElDIiB+ICJTTElDIiwKICAgICAgU3Vic2FtcGxlID09ICJoYWxmYmFzaW5zIiB+ICJIYWxmQmFzaW5zIiwKICAgICAgU3Vic2FtcGxlID09ICJiYXNpbnMiIH4gIkJhc2lucyIsCiAgICAgIFN1YnNhbXBsZSA9PSAiTGFuZGNvdmVyIiB+ICJMYW5kY292ZXIiLAogICAgICBUUlVFIH4gIlJhbmRvbSIKICAgICkKICApCiMgQWRkIHN5bnRoZXRpYyBjYXRlZ29yeSAiQUxMIgpkYXRhX2FsbCA8LSBmaWx0ZXJlZF9kYXRhICU+JQogIG11dGF0ZShMb2NhbGl0eSA9ICJBTEwiKQojIE1lcmdlIGJvdGggZGF0YXNldHMKY29tcGxldGVfZGF0YSA8LSBiaW5kX3Jvd3MoZmlsdGVyZWRfZGF0YSwgZGF0YV9hbGwpCiMgQ3JlYXRlIHBsb3QKcGxvdCA8LSBnZ3Bsb3QoY29tcGxldGVfZGF0YSwgYWVzKHggPSBTYW1wbGVfcGVyY2VudCwgeSA9IFBlYXJzb25fQ29ycmVsYXRpb24pKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZmlsdGVyKGNvbXBsZXRlX2RhdGEsIFN1YnNhbXBsZV9Db2xvciA9PSAiUmFuZG9tIiksCiAgICAgICAgICAgICBhZXMoY29sb3IgPSBTdWJzYW1wbGVfQ29sb3IpLAogICAgICAgICAgICAgYWxwaGEgPSAwLjI1LCBzaXplID0gMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gImJsdWUiLCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAwLjgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gZmlsdGVyKGNvbXBsZXRlX2RhdGEsIFN1YnNhbXBsZV9Db2xvciAhPSAiUmFuZG9tIiksCiAgICAgICAgICAgICBhZXMoY29sb3IgPSBTdWJzYW1wbGVfQ29sb3IpLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoCiAgICAgICJTTElDIiA9ICJwdXJwbGUiLAogICAgICAiSGFsZkJhc2lucyIgPSAic2t5Ymx1ZSIsCiAgICAgICJCYXNpbnMiID0gIm5hdnkiLAogICAgICAiUmFuZG9tIiA9ICJncmF5NTAiLAogICAgICAiTGFuZGNvdmVyIiA9ICJncmVlbiIKICAgICkKICApICsKICBmYWNldF9ncmlkKExvY2FsaXR5IH4gSW5kZXgpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArCiAgbGFicygKICAgIHggPSAiU2FtcGxlIHBlcmNlbnQiLAogICAgeSA9ICJTdWJzYW1wbGVfcGVyZm9ybWFuY2UiLAogICAgY29sb3IgPSAiU2FtcGxpbmcgbWV0aG9kIgogICkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpCiAgKQojIFNhdmUgYXMgUERGIChzZXQgeW91ciBkZXNpcmVkIHBhdGgpCmdnc2F2ZSgKICBmaWxlbmFtZSA9ICIjLzBfU3Vic2FtcGxlcGVyZm9ybWFuY2VfdnNfU2FtcGxlUGVyY2VudF9tZWFuLnBkZiIsCiAgcGxvdCA9IHBsb3QsCiAgd2lkdGggPSAxNS4yNywKICBoZWlnaHQgPSA4LjE1LAogIHVuaXRzID0gImluIgopCgpwcmludChwbG90KQoKCgpgYGAKCiMgT0JKRUNUSVZFIDEgU0laRSBERVBFTkRBTkNFCgpTLiBvYmplY3RpdmUgMSAtIEFuYWx5emUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNhbXBsZSBzaXplIGFuZCB0aGUgc3BhdGlhbCByZXByZXNlbnRhdGl2ZW5lc3Mgb2YgaW50ZXJwb2xhdGVkIHNvdW5kc2NhcGVzIHVzaW5nIGRpZmZlcmVudCBzYW1wbGluZyBzdHJhdGVnaWVzIGluIGhldGVyb2dlbmVvdXMgbGFuZHNjYXBlczsKCiMjIDEuMS4gR2VuZXJhdGUgdGhlIHBlYXJzb24gY29ycmVsYXRpb24gYmV0d2VlbiBTYW1wbGluZyBwZXJjZW50IGFuZCBkZXNpZ24gcHJlY2lzaW9uLgoKVG8gZXZhbHVhdGUgaG93IHNhbXBsaW5nIHNpemUgaW5mbHVlbmNlcyB0aGUgcGVyZm9ybWFuY2Ugb2YgZWFjaCBzdWJzYW1wbGluZyBzdHJhdGVneSwgd2UgY2FsY3VsYXRlZCBhIHNlY29uZCBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50LCBQY29lZjIuIFRoaXMgY29lZmZpY2llbnQgcXVhbnRpZmllcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcHJvcG9ydGlvbiBvZiBzYW1wbGVkIGRhdGEgKGkuZS4sIFNhbXBsZV9wZXJjZW50KSBhbmQgdGhlIHN1YnNhbXBsaW5nIHBlcmZvcm1hbmNlLCBwcmV2aW91c2x5IGNhbGN1bGF0ZWQgYXMgUGNvZWYxIChQZWFyc29uIGNvcnJlbGF0aW9uIGJldHdlZW4gZnVsbC1zYW1wbGUgYW5kIHN1YnNhbXBsZWQgcmFzdGVyIHN1cmZhY2VzKS4KClRoZSBhbmFseXNpcyB3YXMgcGVyZm9ybWVkIGFjcm9zcyBhbGwgY29tYmluYXRpb25zIG9mIGxvY2FsaXRpZXMsIHN1YnNhbXBsaW5nIGRlc2lnbnMsIGZyZXF1ZW5jeSByYW5nZXMsIHRpbWUgcGVyaW9kcywgYWNvdXN0aWMgaW5kaWNlcywgYW5kIHN1bW1hcnkgc3RhdGlzdGljcyAoZS5nLiwgbWVhbiwgbWVkaWFuKS4gRm9yIGVhY2ggdW5pcXVlIGNvbWJpbmF0aW9uLCB3ZSBmaWx0ZXJlZCB0aGUgZGF0YSBhbmQgYXBwbGllZCBnZ3NjYXR0ZXJzdGF0cygpIGZyb20gdGhlIGdnc3RhdHNwbG90IHBhY2thZ2UgdG8gY29tcHV0ZSB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiAoUGNvZWYyKSwgYWxvbmcgd2l0aCBhc3NvY2lhdGVkIHRlc3Qgc3RhdGlzdGljcy4KClRoZSByZXN1bHRpbmcgb3V0cHV0cyB3ZXJlIGNvbnNvbGlkYXRlZCBpbnRvIGEgZGF0YXNldCBuYW1lZCBERjIsIHdoaWNoIHdhcyBsYXRlciB1c2VkIGZvciBzdGF0aXN0aWNhbCBjb21wYXJpc29ucyBiZXR3ZWVuIHN0cmF0ZWdpZXMgYW5kIHZpc3VhbGl6ZWQgdXNpbmcgdmlvbGluIGFuZCBkZW5zaXR5IHBsb3RzLgoKVXNlZCBmaWx0ZXJzOiBcfCBMb2NhbGl0eSBcfCBUeXBlIFx8IEZyZXF1ZW5jeV9SYW5nZSBcfCBUaW1lX1BlcmlvZCBcfCBTdGF0aXN0aWMgXHwgSW5kZXggXHwgUGVhcnNvbl9Db3JyZWxhdGlvbiBcfAoKUmVzdWx0aW5nIHRhYmxlIHdpbGwgYmUgbmFtZWQgIkRGMiIsIHdoaWNoIGluY2x1ZGVzIHRoZSBjYWxjdWxhdGVkIFBjb2VmMi4KCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkoZ2dzdGF0c3Bsb3QpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KG9wZW54bHN4KQpsaWJyYXJ5KGZ1dHVyZS5hcHBseSkKCiMgU2V0IHVwIHBhcmFsbGVsIHBsYW4KcGxhbihtdWx0aXNlc3Npb24sIHdvcmtlcnMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSAtIDEpCgojIExvYWQgZGF0YSAocmVwbGFjZSB3aXRoIGFwcHJvcHJpYXRlIGZpbGUgcGF0aCkKZGF0YSA8LSByZWFkX2V4Y2VsKCIjL0RGMS0xX0ludGVycG9sYXRpb25zX3ZhcmlvZ3JhbXNfYW5kX2Vycm9yX2Zvcl9zdWJzYW1wbGVzLnhsc3giKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoTG9jYWxpdHksIFR5cGUsIFN1YnNhbXBsZSwgRnJlcXVlbmN5X1JhbmdlLCBUaW1lX1BlcmlvZCwgU3RhdGlzdGljLCBJbmRleCksIGFzLmNoYXJhY3RlcikpCgojIENyZWF0ZSBkdXBsaWNhdGUgd2l0aCBMb2NhbGl0eSA9ICJBTEwiCmRhdGFfYWxsIDwtIGRhdGEgJT4lIG11dGF0ZShMb2NhbGl0eSA9ICJBTEwiKQpleHBhbmRlZF9kYXRhIDwtIGJpbmRfcm93cyhkYXRhLCBkYXRhX2FsbCkKCiMgR2V0IHVuaXF1ZSBjb21iaW5hdGlvbnMgb2YgZmlsdGVycwpjb21iaW5hdGlvbnMgPC0gZXhwYW5kZWRfZGF0YSAlPiUKICBkaXN0aW5jdChMb2NhbGl0eSwgVHlwZSwgRnJlcXVlbmN5X1JhbmdlLCBUaW1lX1BlcmlvZCwgU3RhdGlzdGljLCBJbmRleCwgU3Vic2FtcGxlKQoKIyBGdW5jdGlvbiB0byBwcm9jZXNzIGVhY2ggY29tYmluYXRpb24KcHJvY2Vzc19jb21iaW5hdGlvbiA8LSBmdW5jdGlvbihmaWx0ZXJfcm93KSB7CiAgZmlsdGVyZWRfZGF0YSA8LSBleHBhbmRlZF9kYXRhICU+JQogICAgZmlsdGVyKAogICAgICBMb2NhbGl0eSA9PSBmaWx0ZXJfcm93JExvY2FsaXR5LAogICAgICBUeXBlID09IGZpbHRlcl9yb3ckVHlwZSwKICAgICAgRnJlcXVlbmN5X1JhbmdlID09IGZpbHRlcl9yb3ckRnJlcXVlbmN5X1JhbmdlLAogICAgICBUaW1lX1BlcmlvZCA9PSBmaWx0ZXJfcm93JFRpbWVfUGVyaW9kLAogICAgICBTdGF0aXN0aWMgPT0gZmlsdGVyX3JvdyRTdGF0aXN0aWMsCiAgICAgIEluZGV4ID09IGZpbHRlcl9yb3ckSW5kZXgsCiAgICAgIFN1YnNhbXBsZSA9PSBmaWx0ZXJfcm93JFN1YnNhbXBsZQogICAgKQoKICAjIENoZWNrIGZvciBzdWZmaWNpZW50IGRhdGEgYW5kIHZhcmlhdGlvbgogIGlmIChucm93KGZpbHRlcmVkX2RhdGEpIDwgMyB8fAogICAgICBsZW5ndGgodW5pcXVlKGZpbHRlcmVkX2RhdGEkU2FtcGxlX3BlcmNlbnQpKSA8IDIgfHwKICAgICAgbGVuZ3RoKHVuaXF1ZShmaWx0ZXJlZF9kYXRhJFN1YnNhbXBsZV9wZXJmb3JtYW5jZSkpIDwgMikgcmV0dXJuKE5VTEwpCgogICMgRXh0cmFjdCBjb3JyZWxhdGlvbiBzdGF0aXN0aWNzCiAgdGVtcF9wbG90IDwtIHRyeUNhdGNoKHsKICAgIGdnc2NhdHRlcnN0YXRzKAogICAgICBkYXRhID0gZmlsdGVyZWRfZGF0YSwKICAgICAgeCA9IFNhbXBsZV9wZXJjZW50LAogICAgICB5ID0gU3Vic2FtcGxlX3BlcmZvcm1hbmNlLAogICAgICBtZXNzYWdlcyA9IEZBTFNFCiAgICApCiAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSByZXR1cm4oTlVMTCkpCgogIGlmIChpcy5udWxsKHRlbXBfcGxvdCkpIHJldHVybihOVUxMKQoKICBzdGF0cyA8LSB0cnlDYXRjaChleHRyYWN0X3N0YXRzKHRlbXBfcGxvdCksIGVycm9yID0gZnVuY3Rpb24oZSkgcmV0dXJuKE5VTEwpKQogIGlmIChpcy5udWxsKHN0YXRzKSkgcmV0dXJuKE5VTEwpCgogIHN1YnRpdGxlX2RhdGEgPC0gc3RhdHMkc3VidGl0bGVfZGF0YQogIGNhcHRpb25fZGF0YSA8LSBzdGF0cyRjYXB0aW9uX2RhdGEKCiAgIyBBZGQgZmlsdGVyaW5nIGNvbnRleHQgdG8gcmVzdWx0cwogIGZvciAoY29sIGluIG5hbWVzKGZpbHRlcl9yb3cpKSB7CiAgICBzdWJ0aXRsZV9kYXRhW1tjb2xdXSA8LSBmaWx0ZXJfcm93W1tjb2xdXQogICAgY2FwdGlvbl9kYXRhW1tjb2xdXSA8LSBmaWx0ZXJfcm93W1tjb2xdXQogIH0KCiAgc3VidGl0bGVfZGF0YSRUeXBlIDwtICJGcmVxdWVudGlzdCIKICBjYXB0aW9uX2RhdGEkVHlwZSA8LSAiQmF5ZXNpYW4iCgogIGJpbmRfcm93cyhzdWJ0aXRsZV9kYXRhLCBjYXB0aW9uX2RhdGEpCn0KCiMgQXBwbHkgcHJvY2Vzc2luZyB0byBhbGwgY29tYmluYXRpb25zIGluIHBhcmFsbGVsCnJlc3VsdHNfbGlzdCA8LSBmdXR1cmVfbGFwcGx5KDE6bnJvdyhjb21iaW5hdGlvbnMpLCBmdW5jdGlvbihpKSB7CiAgZmlsdGVyX3JvdyA8LSBjb21iaW5hdGlvbnNbaSwgXQogIHByb2Nlc3NfY29tYmluYXRpb24oZmlsdGVyX3JvdykKfSwgZnV0dXJlLnNlZWQgPSBUUlVFKQoKIyBDb21iaW5lIHJlc3VsdHMKZmluYWxfdGFibGUgPC0gYmluZF9yb3dzKHJlc3VsdHNfbGlzdCkKCiMgUmVtb3ZlIGNvbHVtbnMgaW5jb21wYXRpYmxlIHdpdGggRXhjZWwKZmluYWxfdGFibGVfY2xlYW4gPC0gZmluYWxfdGFibGUgJT4lCiAgc2VsZWN0X2lmKH4gIWFueShjbGFzcyguKSAlaW4lIGMoImxpc3QiLCAibGFuZ3VhZ2UiKSkpCgojIEV4cG9ydCBmaW5hbCByZXN1bHQKd3JpdGUueGxzeChmaW5hbF90YWJsZV9jbGVhbiwgIkRGMl9TYW1wbGVTaXplX3ZzX1N1YnNhbXBsZV9wZXJmb3JtYW5jZV9Db3JyZWxhdGlvbnMoUGNvZWZmMikueGxzeCIpCgoKCmBgYAoKIyMgMS4yLiBWaXN1YWwgaW5zcGVjdGlvbiBvZiBzYW1wbGluZyBzaXplIGVmZmVjdHMKClRvIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNhbXBsZSBzaXplIGFuZCBzdWJzYW1wbGluZyBwZXJmb3JtYW5jZSBhY3Jvc3MgZGlmZmVyZW50IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAoZS5nLiwgbG9jYWxpdHksIGluZGV4LCBzdHJhdGVneSksIHdlIGNyZWF0ZWQgYW4gaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiB0b29sIHVzaW5nIGEgU2hpbnkgYXBwbGljYXRpb24uIFRoaXMgdG9vbCBhbGxvd3MgdGhlIGR5bmFtaWMgZ2VuZXJhdGlvbiBvZiB2aW9saW4gcGxvdHMgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIFBjb2VmMiB2YWx1ZXMgKGNvcnJlbGF0aW9uIGJldHdlZW4gc2FtcGxlIHNpemUgYW5kIHN1YnNhbXBsZSBwZXJmb3JtYW5jZSkgYWNyb3NzIHVzZXItZGVmaW5lZCBjYXRlZ29yaWVzLgoKVGhlIGFwcGxpY2F0aW9uIHBlcm1pdHMgZmlsdGVyaW5nIGJ5IG11bHRpcGxlIG1ldGFkYXRhIGZpZWxkcyAoZS5nLiwgZnJlcXVlbmN5IHJhbmdlLCB0aW1lIHBlcmlvZCwgc3RhdGlzdGljLCBvciBhY291c3RpYyBpbmRleCkgYW5kIGR5bmFtaWNhbGx5IHVwZGF0ZXMgdGhlIHZpc3VhbGl6YXRpb24gYWNjb3JkaW5nbHkuIFZpb2xpbiBwbG90cyB3ZXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgZ2dwbG90MiBwYWNrYWdlLCB3aXRoIG9wdGlvbmFsIG92ZXJsYXkgb2Ygaml0dGVyZWQgZGF0YSBwb2ludHMuIFVzZXJzIGNhbiBleHBvcnQgdGhlIHJlc3VsdGluZyBwbG90cyBhcyBQREZzIGZvciByZXBvcnRpbmcgb3Igc3VwcGxlbWVudGFyeSB1c2UuCgpUaGlzIHRvb2wgaXMgYmFzZWQgb24gdGhlIHRhYmxlIERGMiwgYW5kIGZhY2lsaXRhdGVzIHZpc3VhbCBjb21wYXJpc29uIG9mIHRoZSBpbmZsdWVuY2Ugb2Ygc2FtcGxlIHNpemUgYWNyb3NzIGdyb3VwaW5nIGxldmVscyBpbiB0aGUgZGF0YXNldC4KClRoaXMgdmlzdWFsIGluc3BlY3Rpb24gaXMgb25seSBmb3IgQUxMIGRhdGFzZXQuCgpgYGB7cn0KbGlicmFyeShzaGlueSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShkcGx5cikKCnVpIDwtIGZsdWlkUGFnZSgKICB0aXRsZVBhbmVsKCJEaXN0cmlidXRpb24gb2YgUGVhcnNvbiBDb2VmZmljaWVudCAoRnJlcXVlbnRpc3QpIiksCgogIHNpZGViYXJMYXlvdXQoCiAgICBzaWRlYmFyUGFuZWwoCiAgICAgIGZpbGVJbnB1dCgiYXJjaGl2byIsICJVcGxvYWQgRXhjZWwgZmlsZSIsIGFjY2VwdCA9IGMoIi54bHN4IikpLAoKICAgICAgc2VsZWN0SW5wdXQoInZhcmlhYmxlX2NhdGVnb3JpY2EiLCAiQ2F0ZWdvcmljYWwgdmFyaWFibGUgdG8gY29tcGFyZToiLAogICAgICAgICAgICAgICAgICBjaG9pY2VzID0gYygiTG9jYWxpdHkiLCAiRnJlcXVlbmN5X1JhbmdlIiwgIlRpbWVfUGVyaW9kIiwgIlN0YXRpc3RpYyIsICJJbmRleCIsICJTdWJzYW1wbGUiLCAiVHlwZSIpKSwKCiAgICAgIG51bWVyaWNJbnB1dCgiYXhpc190aXRsZV9zaXplIiwgIkF4aXMgdGl0bGUgZm9udCBzaXplOiIsIHZhbHVlID0gMTQsIG1pbiA9IDgsIG1heCA9IDMwKSwKICAgICAgbnVtZXJpY0lucHV0KCJheGlzX3RleHRfc2l6ZSIsICJBeGlzIHRleHQgZm9udCBzaXplOiIsIHZhbHVlID0gMTIsIG1pbiA9IDYsIG1heCA9IDMwKSwKCiAgICAgIGRvd25sb2FkQnV0dG9uKCJkZXNjYXJnYXJfcGRmIiwgIkRvd25sb2FkIHBsb3QgYXMgUERGIiksCgogICAgICB1aU91dHB1dCgiZmlsdHJvc19hZGljaW9uYWxlcyIpCiAgICApLAoKICAgIG1haW5QYW5lbCgKICAgICAgcGxvdE91dHB1dCgiZ3JhZmljb192aW9saW4iLCBoZWlnaHQgPSAiNjAwcHgiKSwKICAgICAgdGFibGVPdXRwdXQoInRhYmxhX2ZpbHRyYWRhIikKICAgICkKICApCikKCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0LCBzZXNzaW9uKSB7CgogICMgUmVhZCB1cGxvYWRlZCBmaWxlCiAgZGF0b3MgPC0gcmVhY3RpdmUoewogICAgcmVxKGlucHV0JGFyY2hpdm8pCiAgICByZWFkX2V4Y2VsKGlucHV0JGFyY2hpdm8kZGF0YXBhdGgpICU+JQogICAgICBmaWx0ZXIoVGlwbyA9PSAiRnJlcXVlbnRpc3QiKSAlPiUKICAgICAgZmlsdGVyKCFpcy5uYShlc3RpbWF0ZSkpCiAgfSkKCiAgIyBEeW5hbWljIGFkZGl0aW9uYWwgZmlsdGVycwogIG91dHB1dCRmaWx0cm9zX2FkaWNpb25hbGVzIDwtIHJlbmRlclVJKHsKICAgIHJlcShkYXRvcygpKQogICAgb3RoZXJfY29sdW1ucyA8LSBzZXRkaWZmKGMoIkxvY2FsaXR5IiwgIkZyZXF1ZW5jeV9SYW5nZSIsICJUaW1lX1BlcmlvZCIsICJTdGF0aXN0aWMiLCAiSW5kZXgiLCAiU3Vic2FtcGxlIiwgIlR5cGUiKSwgaW5wdXQkdmFyaWFibGVfY2F0ZWdvcmljYSkKCiAgICBsYXBwbHkob3RoZXJfY29sdW1ucywgZnVuY3Rpb24oY29sKSB7CiAgICAgIHNlbGVjdElucHV0KAogICAgICAgIGlucHV0SWQgPSBwYXN0ZTAoImZpbHRyb18iLCBjb2wpLAogICAgICAgIGxhYmVsID0gY29sLAogICAgICAgIGNob2ljZXMgPSBjKCJBbGwiLCB1bmlxdWUoZGF0b3MoKVtbY29sXV0pKSwKICAgICAgICBzZWxlY3RlZCA9ICJBbGwiCiAgICAgICkKICAgIH0pCiAgfSkKCiAgIyBGaWx0ZXIgZGF0YSBiYXNlZCBvbiBzZWxlY3RlZCBpbnB1dHMKICBkYXRvc19maWx0cmFkb3MgPC0gcmVhY3RpdmUoewogICAgcmVxKGRhdG9zKCkpCiAgICBkZiA8LSBkYXRvcygpCiAgICBvdGhlcl9jb2x1bW5zIDwtIHNldGRpZmYoYygiTG9jYWxpdHkiLCAiRnJlcXVlbmN5X1JhbmdlIiwgIlRpbWVfUGVyaW9kIiwgIlN0YXRpc3RpYyIsICJJbmRleCIsICJTdWJzYW1wbGUiLCAiVHlwZSIpLCBpbnB1dCR2YXJpYWJsZV9jYXRlZ29yaWNhKQoKICAgIGZvciAoY29sIGluIG90aGVyX2NvbHVtbnMpIHsKICAgICAgdmFsIDwtIGlucHV0W1twYXN0ZTAoImZpbHRyb18iLCBjb2wpXV0KICAgICAgaWYgKCFpcy5udWxsKHZhbCkgJiYgdmFsICE9ICJBbGwiKSB7CiAgICAgICAgZGYgPC0gZGYgJT4lIGZpbHRlciguZGF0YVtbY29sXV0gPT0gdmFsKQogICAgICB9CiAgICB9CgogICAgZGYKICB9KQoKICAjIEdlbmVyYXRlIHZpb2xpbiBwbG90CiAgcGxvdF92aW9saW5lcyA8LSByZWFjdGl2ZSh7CiAgICBkZiA8LSBkYXRvc19maWx0cmFkb3MoKQogICAgcmVxKG5yb3coZGYpID4gMCkKCiAgICBnZ3Bsb3QoZGYsIGFlcyh4ID0gLmRhdGFbW2lucHV0JHZhcmlhYmxlX2NhdGVnb3JpY2FdXSwgeSA9IGVzdGltYXRlKSkgKwogICAgICBnZW9tX3Zpb2xpbihmaWxsID0gInNreWJsdWUiLCBhbHBoYSA9IDAuNywgY29sb3IgPSBOQSkgKwogICAgICAjIGdlb21faml0dGVyKHdpZHRoID0gMC4xNSwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUsIGNvbG9yID0gImJsYWNrIikgKwogICAgICBsYWJzKHggPSBpbnB1dCR2YXJpYWJsZV9jYXRlZ29yaWNhLCB5ID0gIlBlYXJzb24gRXN0aW1hdGUiKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIHRoZW1lKAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGlucHV0JGF4aXNfdGl0bGVfc2l6ZSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBpbnB1dCRheGlzX3RleHRfc2l6ZSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKQogICAgICApCiAgfSkKCiAgb3V0cHV0JGdyYWZpY29fdmlvbGluIDwtIHJlbmRlclBsb3QoewogICAgcGxvdF92aW9saW5lcygpCiAgfSkKCiAgIyBTaG93IGZpbHRlcmVkIHRhYmxlCiAgb3V0cHV0JHRhYmxhX2ZpbHRyYWRhIDwtIHJlbmRlclRhYmxlKHsKICAgIGRhdG9zX2ZpbHRyYWRvcygpCiAgfSkKCiAgIyBEb3dubG9hZCBidXR0b24KICBvdXRwdXQkZGVzY2FyZ2FyX3BkZiA8LSBkb3dubG9hZEhhbmRsZXIoCiAgICBmaWxlbmFtZSA9IGZ1bmN0aW9uKCkgewogICAgICBwYXN0ZTAoInZpb2xpbl9wbG90X3BlYXJzb25fIiwgU3lzLkRhdGUoKSwgIi5wZGYiKQogICAgfSwKICAgIGNvbnRlbnQgPSBmdW5jdGlvbihmaWxlKSB7CiAgICAgIGdnc2F2ZShmaWxlLCBwbG90ID0gcGxvdF92aW9saW5lcygpLCBkZXZpY2UgPSAicGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKICAgIH0KICApCn0KCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKCmBgYAoKIyMgMS4zLiBOb3JtYWxpdHkgYXNzZXNzbWVudAoKQmVmb3JlIGEgc3RhdGlzdGljYWwgdGVzdCB0byBldmFsdWF0ZSB0aGUgc2l6ZSBkZXBlbmRhbmNlLCBub3JtYWxpdHkgbXVzdCBiZSBjaGVja2VkLiBUbyBkZXRlcm1pbmUgd2hldGhlciBwYXJhbWV0cmljIHRlc3RzIGNvdWxkIGJlIGFwcGxpZWQgdG8gY29tcGFyZSB0aGUgc2FtcGxpbmcgc3RyYXRlZ2llcywgd2UgZXZhbHVhdGVkIHRoZSBkaXN0cmlidXRpb24gb2YgUGNvZWYyIHZhbHVlcyAoaS5lLiwgY29ycmVsYXRpb25zIGJldHdlZW4gc2FtcGxpbmcgcHJvcG9ydGlvbiBhbmQgc3Vic2FtcGxlIHBlcmZvcm1hbmNlKSBhY3Jvc3MgYWxsIHNhbXBsaW5nIGRlc2lnbnMuIFdlIGFwcGxpZWQgdGhlIFNoYXBpcm/igJNXaWxrIHRlc3QgZm9yIG5vcm1hbGl0eSB3aXRoaW4gZWFjaCBzdWJzYW1wbGUgY2F0ZWdvcnkgdXNpbmcgdGhlIHJzdGF0aXggcGFja2FnZS4gQWRkaXRpb25hbGx5LCB3ZSB2aXN1YWxseSBpbnNwZWN0ZWQgdGhlIGRpc3RyaWJ1dGlvbnMgYnkgcGxvdHRpbmcgaGlzdG9ncmFtcyB3aXRoIGRlbnNpdHkgY3VydmVzLCBmYWNldGVkIGJ5IHN1YnNhbXBsZSBzdHJhdGVneSAoZS5nLiwgYmFzaW5zLCBTTElDLCBzc2FtcGxlNDApLgoKUmVzdWx0cyBmcm9tIHRoZSBTaGFwaXJv4oCTV2lsayB0ZXN0cyBhbmQgdmlzdWFsIGFzc2Vzc21lbnRzIHJldmVhbGVkIHdpZGVzcHJlYWQgZGV2aWF0aW9ucyBmcm9tIG5vcm1hbGl0eSwganVzdGlmeWluZyB0aGUgdXNlIG9mIG5vbi1wYXJhbWV0cmljIHN0YXRpc3RpY2FsIHRlc3RzIGluIHN1YnNlcXVlbnQgYW5hbHlzZXMuIEFsbCByZXN1bHRzIHdlcmUgc2F2ZWQgYXMgcGFydCBvZiB0aGUgcmVwcm9kdWNpYmxlIHdvcmtmbG93LCBpbmNsdWRpbmcgdGhlIHRlc3QgcmVzdWx0cyBhbmQgZGlzdHJpYnV0aW9uIHBsb3RzLgoKVGhlIGlucHV0IGlzIERGMl9TYW1wbGVTaXplX3ZzX1N1YnNhbXBsZV9wZXJmb3JtYW5jZV9Db3JyZWxhdGlvbnMoUGNvZWZmMikueGxzeC4gUHJvY2VkdXJlIG11c3QgYmUgZG9uZSBmb3IgbWVhbiBhbmQgbWVkaWFuCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIHBhY2thZ2VzCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocnN0YXRpeCkgICAjIGZvciBub3JtYWxpdHkgdGVzdHMgYW5kIHN1bW1hcmllcwpsaWJyYXJ5KGdncHVicikgICAgIyBmb3IgdmlzdWFsaXphdGlvbgoKIyBMb2FkIGRhdGFzZXQgKHJlcGxhY2Ugd2l0aCBjb3JyZWN0IGZpbGUgcGF0aCkKZGF0YSA8LSByZWFkX2V4Y2VsKCIjL0RGMl9TYW1wbGVTaXplX3ZzX1N1YnNhbXBsZV9wZXJmb3JtYW5jZV9Db3JyZWxhdGlvbnMoUGNvZWZmMikueGxzeCIpCiMgRmlsdGVyIG9ubHkgRnJlcXVlbnRpc3QgYW5hbHlzZXMsIHJlbW92ZSBOQSwgYW5kIGtlZXAgU3RhdGlzdGljID09ICJtZWFuIgpkYXRhX2ZyZWMgPC0gZGF0YSAlPiUKICBmaWx0ZXIoCiAgICBUaXBvID09ICJGcmVxdWVudGlzdCIsCiAgICAhaXMubmEoZXN0aW1hdGUpLAogICAgU3RhdGlzdGljID09ICJtZWFuIiAgICMgQ2hhbmdlIGhlcmUgaWYgeW91IHdhbnQgdG8gdXNlICJtZWRpYW4iLCBldGMuCiAgKQoKCiMgUGVyZm9ybSBTaGFwaXJvLVdpbGsgbm9ybWFsaXR5IHRlc3QgYnkgU3Vic2FtcGxlCm5vcm1hbGl0eSA8LSBkYXRhX2ZyZWMgJT4lCiAgZ3JvdXBfYnkoU3Vic2FtcGxlKSAlPiUKICBzaGFwaXJvX3Rlc3QoZXN0aW1hdGUpCgpwcmludCgiIyMjIFNoYXBpcm8tV2lsayBub3JtYWxpdHkgdGVzdCBieSBTdWJzYW1wbGU6IikKcHJpbnQobm9ybWFsaXR5KQoKIyBDcmVhdGUgaGlzdG9ncmFtIGFuZCBkZW5zaXR5IHBsb3RzCgpwbG90IDwtIGdncGxvdChkYXRhX2ZyZWMsIGFlcyh4ID0gZXN0aW1hdGUsIGZpbGwgPSBTdWJzYW1wbGUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjUsIGJpbnMgPSAzMCkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNykgKwogIGZhY2V0X3dyYXAoflN1YnNhbXBsZSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKQogICkgKwogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gIlBlYXJzb24gRXN0aW1hdGUiLCB5ID0gIkRlbnNpdHkiKQoKIyBTYXZlIHBsb3QgdG8gUERGICh1cGRhdGUgZmlsZSBwYXRoKQpnZ3NhdmUoCiAgZmlsZW5hbWUgPSAiIy9SMS0zX21lYW5fRGlzdHJpYnV0aW9uX0VzdGltYXRlcy5wZGYiLAogIHBsb3QgPSBwbG90LAogIHdpZHRoID0gMTUuMjcsCiAgaGVpZ2h0ID0gOC4xNSwKICB1bml0cyA9ICJpbiIKKQoKIyBEaXNwbGF5IHBsb3QKcGxvdAoKIyBFeHBvcnQgbm9ybWFsaXR5IHRlc3QgcmVzdWx0cwpsaWJyYXJ5KHdyaXRleGwpCndyaXRlX3hsc3gobm9ybWFsaXR5LCAiIy9SMS0zX21lYW5fU2hhcGlyb19Ob3JtYWxpdHlfVGVzdC54bHN4IikKCgpgYGAKCiMjIDEuNC4gRGVwZW5kZW5jZSBvZiBzdWJzYW1wbGluZyBzdHJhdGVnaWVzIG9uIHNhbXBsZSBzaXplCgpUbyBldmFsdWF0ZSB3aGV0aGVyIGRpZmZlcmVudCBzdWJzYW1wbGluZyBzdHJhdGVnaWVzIGV4aGliaXQgZGlzdGluY3QgbGV2ZWxzIG9mIHNlbnNpdGl2aXR5IHRvIHNhbXBsZSBzaXplLCB3ZSBjb21wYXJlZCB0aGUgc3RyZW5ndGggb2YgdGhlIGNvcnJlbGF0aW9uIChQY29lZjIpIGJldHdlZW4gc2FtcGxlIHNpemUgKGBTYW1wbGVfcGVyY2VudGApIGFuZCBzdWJzYW1wbGluZyBwZXJmb3JtYW5jZSBhY3Jvc3Mgc3RyYXRlZ2llcy4KCldlIGZpcnN0IGZpbHRlcmVkIERGMiB0byBpbmNsdWRlIG9ubHkgZnJlcXVlbnRpc3QgZXN0aW1hdGVzIHdoZXJlIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIHdhcyBjb21wdXRlZCBiZXR3ZWVuIHNhbXBsZSBzaXplIGFuZCBkZXNpZ24gcGVyZm9ybWFuY2UgKGBwYXJhbWV0ZXIxID09IFNhbXBsZV9wZXJjZW50YCBhbmQgYHBhcmFtZXRlcjIgPT0gUGVhcnNvbl9Db3JyZWxhdGlvbmApIHVzaW5nIHRoZSBtZWFuIHN0YXRpc3RpYy4KClNhbXBsaW5nIHN0cmF0ZWdpZXMgd2VyZSB0aGVuIGdyb3VwZWQgaW50byB0d28gY2F0ZWdvcmllczogYCJyYW5kb20iYCAoZS5nLiwgYHNzYW1wbGUqYCkgYW5kIGAidGVzc2VsbGF0aW9uImAgKGUuZy4sIGdyaWQtYmFzZWQgZGVzaWducyBzdWNoIGFzIGBTTElDYCBvciBgYmFzaW5zYCkuIEZvciBlYWNoIGdyb3VwLCB3ZSBzdW1tYXJpemVkIHRoZSBkaXN0cmlidXRpb24gb2YgUGNvZWYyIHZhbHVlcyB0aHJvdWdoIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgKG1lYW4sIG1lZGlhbiwgU0QsIElRUiwgQ1YpLgoKR2l2ZW4gdGhlIGxhY2sgb2Ygbm9ybWFsaXR5IChhcyBwcmV2aW91c2x5IGFzc2Vzc2VkKSwgd2UgZW1wbG95ZWQgYSBub24tcGFyYW1ldHJpYyBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0IHRvIGNvbXBhcmUgUGNvZWYyIGRpc3RyaWJ1dGlvbnMgYmV0d2VlbiB0aGUgdHdvIHN0cmF0ZWd5IHR5cGVzLgoKRHVlIHRvIHRoZSBsYWNrIG9mIG5vcm1hbGl0eSwgYSAqKldpbGNveG9uIHJhbmstc3VtIHRlc3QqKiB3YXMgdXNlZCB0byBjb21wYXJlIHRoZSBkaXN0cmlidXRpb25zIG9mIFBjb2VmMiBiZXR3ZWVuIGdyb3Vwcy4gV2UgYWxzbyBhcHBsaWVkIGEKRmxpZ25lcuKAk0tpbGxlZW4gdGVzdCB0byBldmFsdWF0ZSBkaWZmZXJlbmNlcyBpbiBkaXNwZXJzaW9uIGJldHdlZW4gc3RyYXRlZ2llcy4KCkFsbCByZXN1bHRzIHdlcmUgdmlzdWFsaXplZCB1c2luZyB2aW9saW4gYW5kIGJveHBsb3RzLiBTdW1tYXJ5IHRhYmxlcyBhbmQgdGVzdCBvdXRwdXRzIHdlcmUgZXhwb3J0ZWQgZm9yIHJlcHJvZHVjaWJpbGl0eS4KCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KHdyaXRleGwpCmxpYnJhcnkoZ2dwbG90MikKCiMgTG9hZCByZXN1bHRzIHRhYmxlIERGMiAoYWRqdXN0IHBhdGgpCmRhdGEgPC0gcmVhZF9leGNlbCgiIy9ERjJfU2FtcGxlU2l6ZV92c19TdWJzYW1wbGVfcGVyZm9ybWFuY2VfQ29ycmVsYXRpb25zKFBjb2VmZjIpLnhsc3giKQoKIyBGaWx0ZXIgdmFsaWQgUGVhcnNvbiBjb3JyZWxhdGlvbnMgYmV0d2VlbiBTYW1wbGVfcGVyY2VudCBhbmQgUGVhcnNvbl9Db3JyZWxhdGlvbiAoRnJlcXVlbnRpc3QsIFN0YXRpc3RpYyA9ICJtZWRpYW4iKQpkYXRhX2ZyZWMgPC0gZGF0YSAlPiUKICBmaWx0ZXIoCiAgICBwYXJhbWV0ZXIxID09ICJTYW1wbGVfcGVyY2VudCIsCiAgICBwYXJhbWV0ZXIyID09ICJTdWJzYW1wbGVfcGVyZm9ybWFuY2UiLAogICAgZWZmZWN0c2l6ZSA9PSAiUGVhcnNvbiBjb3JyZWxhdGlvbiIsCiAgICBUaXBvID09ICJGcmVxdWVudGlzdCIsCiAgICBTdGF0aXN0aWMgPT0gIm1lZGlhbiIsCiAgICAhaXMubmEoZXN0aW1hdGUpCiAgKQoKIyBDbGFzc2lmeSBzYW1wbGluZyBzdHJhdGVneQpkYXRhX2ZyZWMgPC0gZGF0YV9mcmVjICU+JQogIG11dGF0ZShUeXBlX2dyb3VwID0gY2FzZV93aGVuKAogICAgZ3JlcGwoIl5zc2FtcGxlIiwgU3Vic2FtcGxlKSB+ICJyYW5kb20iLAogICAgVFJVRSB+ICJ0ZXNzZWxsYXRpb24iCiAgKSkKCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgUGNvZWYyIGJ5IHN0cmF0ZWd5IGdyb3VwCnN1bW1hcnlfZGVwZW5kZW5jeSA8LSBkYXRhX2ZyZWMgJT4lCiAgZ3JvdXBfYnkoVHlwZV9ncm91cCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIG1lYW5fUGNvZWYyID0gbWVhbihlc3RpbWF0ZSwgbmEucm0gPSBUUlVFKSwKICAgIG1lZGlhbl9QY29lZjIgPSBtZWRpYW4oZXN0aW1hdGUsIG5hLnJtID0gVFJVRSksCiAgICBzZF9QY29lZjIgPSBzZChlc3RpbWF0ZSwgbmEucm0gPSBUUlVFKSwKICAgIGlxcl9QY29lZjIgPSBJUVIoZXN0aW1hdGUsIG5hLnJtID0gVFJVRSksCiAgICBjdl9QY29lZjIgPSBzZChlc3RpbWF0ZSwgbmEucm0gPSBUUlVFKSAvIGFicyhtZWFuKGVzdGltYXRlLCBuYS5ybSA9IFRSVUUpKQogICkKCnByaW50KCJTdW1tYXJ5IG9mIHNhbXBsZSBzaXplIGRlcGVuZGVuY3kgYnkgc3RyYXRlZ3kgZ3JvdXA6IikKcHJpbnQoc3VtbWFyeV9kZXBlbmRlbmN5KQoKIyBXaWxjb3hvbiByYW5rLXN1bSB0ZXN0CndpbGNveCA8LSB3aWxjb3gudGVzdChlc3RpbWF0ZSB+IFR5cGVfZ3JvdXAsIGRhdGEgPSBkYXRhX2ZyZWMpCnByaW50KCJXaWxjb3hvbiB0ZXN0IGJldHdlZW4gcmFuZG9tIGFuZCB0ZXNzZWxsYXRpb24gc3RyYXRlZ2llczoiKQpwcmludCh3aWxjb3gpCgojIEZpc2hlcidzIFogY29tcGFyaXNvbiBvZiBjb3JyZWxhdGlvbiBzdHJlbmd0aAoKcmFuZG9tIDwtIGRhdGFfZnJlYyAlPiUgZmlsdGVyKFR5cGVfZ3JvdXAgPT0gInJhbmRvbSIpCnRlc3MgPC0gZGF0YV9mcmVjICU+JSBmaWx0ZXIoVHlwZV9ncm91cCA9PSAidGVzc2VsbGF0aW9uIikKCmZpc2hlcnogPC0gci50ZXN0KAogIG4gPSBucm93KHJhbmRvbSksIHIxMiA9IGNvcihyYW5kb20kYFNhbXBsZSBwZXJjZW50YCwgcmFuZG9tJGVzdGltYXRlKSwKICBuMiA9IG5yb3codGVzcyksIHIzNCA9IGNvcih0ZXNzJGBTYW1wbGUgcGVyY2VudGAsIHRlc3MkZXN0aW1hdGUpCikKCnByaW50KCJGaXNoZXIncyBaIHRlc3QgZm9yIGNvcnJlbGF0aW9uIHN0cmVuZ3RoOiIpCnByaW50KGZpc2hlcnopCiMgRmxpZ25lcuKAk0tpbGxlZW4gdGVzdCBmb3IgZGlzcGVyc2lvbiBkaWZmZXJlbmNlcwpmbGlnbmVyIDwtIGZsaWduZXIudGVzdChlc3RpbWF0ZSB+IFR5cGVfZ3JvdXAsIGRhdGEgPSBkYXRhX2ZyZWMpCnByaW50KCJGbGlnbmVy4oCTS2lsbGVlbiB0ZXN0IGZvciB2YXJpYW5jZSBkaWZmZXJlbmNlczoiKQpwcmludChmbGlnbmVyKQoKIyBPcHRpb25hbCBwbG90OiBkaXN0cmlidXRpb24gb2YgUGNvZWYyIHZhbHVlcwpnZ3Bsb3QoZGF0YV9mcmVjLCBhZXMoeCA9IFR5cGVfZ3JvdXAsIHkgPSBlc3RpbWF0ZSwgZmlsbCA9IFR5cGVfZ3JvdXApKSArCiAgZ2VvbV92aW9saW4oYWxwaGEgPSAwLjUpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjIsIG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPSAwLjgpICsKICBsYWJzKHRpdGxlID0gIlNhbXBsZSBzaXplIGRlcGVuZGVuY2UgKFBjb2VmMikiLCB5ID0gIlBjb2VmMiAoY29ycmVsYXRpb24pIiwgeCA9ICJTYW1wbGluZyBzdHJhdGVneSIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDEpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCkKCiMgRXhwb3J0IHZhbHVlcyBhbmQgc3VtbWFyaWVzCndyaXRlX3hsc3goCiAgbGlzdCgKICAgIFBjb2VmMl9WYWx1ZXMgPSBkYXRhX2ZyZWMsCiAgICBHcm91cF9TdW1tYXJ5ID0gc3VtbWFyeV9kZXBlbmRlbmN5CiAgKSwKICBwYXRoID0gIiMvUjEtNF9NRURJQU5fU0FNUExJTkdfU1RSQVRFR1lfQ09NUEFSSVNPTi54bHN4IgopCiMgRXhwb3J0IEYtdGVzdCByZXN1bHRzIChNRURJQU4pCgp3cml0ZV94bHN4KAogIGxpc3QoCiAgICBQY29lZjJfU3ByZWFkX1N1bW1hcnkgPSBzdW1tYXJ5X2RlcGVuZGVuY3ksCiAgICBGX1Rlc3RfVmFyaWFuY2UgPSBhcy5kYXRhLmZyYW1lKHQoYygKICAgICAgRl9zdGF0aXN0aWMgPSAwLjc5NTY2LAogICAgICBkZjEgPSAxNjcsCiAgICAgIGRmMiA9IDE1MiwKICAgICAgcF92YWx1ZSA9IDAuMTQ5LAogICAgICBDSV9sb3dlciA9IDAuNTgxODI2MiwKICAgICAgQ0lfdXBwZXIgPSAxLjA4NTU2OTcKICAgICkpKQogICksCiAgcGF0aCA9ICIjL1IxLTRfTUVESUFOX1Bjb2VmMl9WQVJJQU5DRV9URVNULnhsc3giCikKCiMgRXhwb3J0IEYtdGVzdCByZXN1bHRzIChNRUFOKQp3cml0ZV94bHN4KAogIGxpc3QoCiAgICBQY29lZjJfU3ByZWFkX1N1bW1hcnkgPSBzdW1tYXJ5X2RlcGVuZGVuY3ksCiAgICBGX1Rlc3RfVmFyaWFuY2UgPSBhcy5kYXRhLmZyYW1lKHQoYygKICAgICAgRl9zdGF0aXN0aWMgPSAwLjcwNTc3LAogICAgICBkZjEgPSAxNjcsCiAgICAgIGRmMiA9IDE2MywKICAgICAgcF92YWx1ZSA9IDAuMDI1NjcsCiAgICAgIENJX2xvd2VyID0gMC41MTk0Mzk2LAogICAgICBDSV91cHBlciA9IDAuOTU4Mzc3NwogICAgKSkpCiAgKSwKICBwYXRoID0gIiMvUjEtNF9NRUFOX1Bjb2VmMl9WQVJJQU5DRV9URVNULnhsc3giCikKCiMgU2F2ZSBmaW5hbCBwbG90IGFzIFBERgpmaW5hbF9wbG90IDwtIGdncGxvdChkYXRhX2ZyZWMsIGFlcyh4ID0gVHlwZV9ncm91cCwgeSA9IGVzdGltYXRlLCBmaWxsID0gVHlwZV9ncm91cCkpICsKICBnZW9tX3Zpb2xpbihhbHBoYSA9IDAuNSwgdHJpbSA9IEZBTFNFKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yLCBvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC44KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygicmFuZG9tIiA9ICIjRjg3NjZEIiwgInRlc3NlbGxhdGlvbiIgPSAiIzAwQkZDNCIpKSArCiAgbGFicyh0aXRsZSA9ICJTYW1wbGUgc2l6ZSBkZXBlbmRlbmN5IChQY29lZjIpIiwKICAgICAgIHkgPSAiUGNvZWYyIChjb3JyZWxhdGlvbikiLAogICAgICAgeCA9ICJTYW1wbGluZyBzdHJhdGVneSIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLCAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xLCAxKSwgb29iID0gc2NhbGVzOjpzcXVpc2gpCgpnZ3NhdmUoCiAgZmlsZW5hbWUgPSAiIy9SMS00X01FRElBTl9QY29lZjJfU0FNUExJTkdfU1RSQVRFR1kucGRmIiwKICBwbG90ID0gZmluYWxfcGxvdCwKICB3aWR0aCA9IDgsCiAgaGVpZ2h0ID0gNiwKICB1bml0cyA9ICJpbiIKKQoKYGBgCgojIyMjIyAKCiMgT0JKRUNUSVZFIDI6IEVYUExPUkUgRUZGRUNUSVZFTkVTUyBPRiBTVFJBVElGSUVEIFNBTVBMSU5HIERFU0lHTlMKCkNvbXBhcmUgdGhlIHBlcmZvcm1hbmNlIG9mIGRpZmZlcmVudCBzYW1wbGluZyBzdHJhdGVnaWVzLCBpbmNsdWRpbmcgcmFuZG9tIGFuZCBzdHJhdGlmaWVkIGFwcHJvYWNoZXMsIGdlbmFyYXRlZCBieSBzZWdtZW50YXRpb24gbWV0aG9kcy4KClRvIGFzc2VzcyB0aGUgZWZmZWN0aXZlbmVzcyBvZiB0ZXNzZWxsYXRpb24tYmFzZWQgc2FtcGxpbmcgc3RyYXRlZ2llcywgd2UgY29uZHVjdGVkIGEgbXVsdGktc3RlcCBzdGF0aXN0aWNhbCBhbmFseXNpcyB1c2luZyBSLiBGaXJzdCwgd2UgY2FsY3VsYXRlZCB0d28gbWV0cmljcyBmb3IgZWFjaCBzdWJzYW1wbGU6ICgxKSBzdWJzYW1wbGUgcGVyZm9ybWFuY2UgaW4gdGhlIGZvcm0gb2YgUGVhcnNvbiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzdWJzYW1wbGUgYW5kIGl0cyBmdWxsIHJlZmVyZW5jZSBkYXRhc2V0OyBhbmQgKDIpIHNhbXBsaW5nIGVmZmljaWVuY3ksIGNvbXB1dGVkIGFzIHRoZSByYXRpbyBiZXR3ZWVuIFBlYXJzb24gY29ycmVsYXRpb24gYW5kIHRoZSBzYW1wbGluZyBlZmZvcnQgKFN1YnNhbXBsZSBwZXJmb3JtYW5jZS9TYW1wbGVfcGVyY2VudCkuCgpXZSB0aGVuIGdyb3VwZWQgZGF0YSBieSBzdW1tYXJ5IHN0YXRpc3RpYyB0eXBlIChtZWFuIG9yIG1lZGlhbikgYW5kIGNvbXB1dGVkIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgZm9yIGVhY2ggdGVzc2VsbGF0aW9uIHN0cmF0ZWd5LCBpbmNsdWRpbmcgc2FtcGxlIHNpemUsIGNlbnRyYWwgdGVuZGVuY3kgKG1lYW4sIG1lZGlhbiksIGRpc3BlcnNpb24gKHN0YW5kYXJkIGRldmlhdGlvbiksIGFuZCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24uCgpOb3JtYWxpdHkgb2YgUGVhcnNvbiBjb3JyZWxhdGlvbnMgd2FzIGFzc2Vzc2VkIHVzaW5nIHRoZSBTaGFwaXJv4oCTV2lsayB0ZXN0IHdpdGhpbiBlYWNoIHN1YnNhbXBsaW5nIGdyb3VwLCB1c2luZyBzaGFwaXJvX3Rlc3QoKSBmcm9tIHRoZSByc3RhdGl4IHBhY2thZ2UuCgpHaXZlbiB3aWRlc3ByZWFkIG5vbi1ub3JtYWxpdHksIHdlIGFwcGxpZWQgS3J1c2thbOKAk1dhbGxpcyByYW5rLXN1bSB0ZXN0cyB0byBjb21wYXJlIGJvdGggcmF3IHBlcmZvcm1hbmNlIGFuZCBlZmZpY2llbmN5IGFjcm9zcyBzdWJzYW1wbGluZyBzdHJhdGVnaWVzLiBXaGVyZSBkaWZmZXJlbmNlcyB3ZXJlIGRldGVjdGVkLCB3ZSB1c2VkIER1bm7igJlzIHBvc3QtaG9jIHRlc3RzIHdpdGggQmVuamFtaW5p4oCTSG9jaGJlcmcgY29ycmVjdGlvbiB0byBldmFsdWF0ZSBwYWlyd2lzZSBjb250cmFzdHMuCgpWaW9saW4gYW5kIGJveHBsb3RzIHdlcmUgZ2VuZXJhdGVkIHRvIHZpc3VhbGx5IGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBib3RoIHBlcmZvcm1hbmNlIGFuZCBlZmZpY2llbmN5IGFjcm9zcyBzdWJzYW1wbGluZyBtZXRob2RzLiBBbGwgcHJvY2VkdXJlcyB3ZXJlIHJ1biBzZXBhcmF0ZWx5IGZvciBtZWFuIGFuZCBtZWRpYW4gc3RhdGlzdGljcywgYW5kIHJlc3VsdHMgKHN1bW1hcnkgdGFibGVzIGFuZCBwbG90cykgd2VyZSBleHBvcnRlZCB0byBQREYgYW5kIEV4Y2VsIGZvcm1hdHMuCgpQYWNrYWdlcyB3ZSB1c2VkOiBkcGx5ciwgZ2dwbG90MiwgZ2dwdWJyLCByc3RhdGl4LCBGU0EsIHdyaXRleGwuCgpUaGUgZW50cnkgZGF0YWJhc2UgaXM6IERGMS0xX0ludGVycG9sYXRpb25zX3ZhcmlvZ3JhbXNfYW5kIGVycm9yX2Zvcl9zdWJzYW1wbGVzLnhsc3gKCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHJzdGF0aXgpCmxpYnJhcnkoRlNBKQpsaWJyYXJ5KHdyaXRleGwpCgojIExvYWQgZGF0YSAocmVwbGFjZSBwYXRoIGFjY29yZGluZ2x5KQpkZiA8LSByZWFkX2V4Y2VsKCIjL0RGMS0xX0ludGVycG9sYXRpb25zX3ZhcmlvZ3JhbXNfYW5kX2Vycm9yX2Zvcl9zdWJzYW1wbGVzLnhsc3giKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoU3Vic2FtcGxlLCBUeXBlLCBJbmRleCwgU3RhdGlzdGljKSwgYXMuY2hhcmFjdGVyKSkgJT4lCiAgbXV0YXRlKFBlYXJzb25fcmVsID0gUGVhcnNvbl9Db3JyZWxhdGlvbiAvIFNhbXBsZV9wZXJjZW50KQoKIyBMb29wIHRocm91Z2ggZWFjaCBzdW1tYXJ5IHN0YXRpc3RpYyB0eXBlCmZvciAoc3RhdCBpbiBjKCJtZWFuIiwgIm1lZGlhbiIpKSB7CiAgCiAgZGZfdGVzcyA8LSBkZiAlPiUKICAgIGZpbHRlcihUeXBlID09ICJUZXNzZWxscyIsIFN0YXRpc3RpYyA9PSBzdGF0LCAhaXMubmEoUGVhcnNvbl9Db3JyZWxhdGlvbikpCiAgCiAgIyBTdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgcHJlY2lzaW9uIGFuZCBlZmZpY2llbmN5CiAgc3VtbWFyeV9wcmVjaXNpb24gPC0gZGZfdGVzcyAlPiUKICAgIGdyb3VwX2J5KFN1YnNhbXBsZSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG4gPSBuKCksCiAgICAgIG1lYW5fUGVhcnNvbiA9IG1lYW4oUGVhcnNvbl9Db3JyZWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgICAgbWVkaWFuX1BlYXJzb24gPSBtZWRpYW4oUGVhcnNvbl9Db3JyZWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgICAgc2RfUGVhcnNvbiA9IHNkKFBlYXJzb25fQ29ycmVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICAgIG1lYW5fZWZmID0gbWVhbihQZWFyc29uX3JlbCwgbmEucm0gPSBUUlVFKSwKICAgICAgbWVkaWFuX2VmZiA9IG1lZGlhbihQZWFyc29uX3JlbCwgbmEucm0gPSBUUlVFKSwKICAgICAgc2RfZWZmID0gc2QoUGVhcnNvbl9yZWwsIG5hLnJtID0gVFJVRSksCiAgICAgIGN2X2VmZiA9IHNkX2VmZiAvIGFicyhtZWFuX2VmZikKICAgICkgJT4lCiAgICBhcnJhbmdlKGRlc2MobWVkaWFuX2VmZikpCiAgCiAgIyBTaGFwaXJvLVdpbGsgbm9ybWFsaXR5IHRlc3QgKG9ubHkgZm9yIGdyb3VwcyB3aXRoIG4gPj0gMykKICAKICB2YWxpZCA8LSBkZl90ZXNzICU+JQogICAgZ3JvdXBfYnkoU3Vic2FtcGxlKSAlPiUKICAgIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICAgIGZpbHRlcihuID49IDMpICU+JQogICAgcHVsbChTdWJzYW1wbGUpCiAgCiAgbm9ybWFsaXR5X2RmIDwtIGRmX3Rlc3MgJT4lCiAgICBmaWx0ZXIoU3Vic2FtcGxlICVpbiUgdmFsaWQpICU+JQogICAgZ3JvdXBfYnkoU3Vic2FtcGxlKSAlPiUKICAgIHNoYXBpcm9fdGVzdChQZWFyc29uX0NvcnJlbGF0aW9uKQoKICAKICAjIFByZWNpc2lvbiBwbG90CiAgcHJlY2lzaW9uX3Bsb3QgPC0gZ2dwbG90KGRmX3Rlc3MsIGFlcyh4ID0gU3Vic2FtcGxlLCB5ID0gUGVhcnNvbl9Db3JyZWxhdGlvbiwgZmlsbCA9IFN1YnNhbXBsZSkpICsKICAgIGdlb21fdmlvbGluKHRyaW0gPSBGQUxTRSkgKwogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlN0cmF0ZWd5IHByZWNpc2lvbiAoUGVhcnNvbikgLSIsIHN0YXQpLCB5ID0gIlBlYXJzb24gQ29ycmVsYXRpb24iKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgMSksIG9vYiA9IHNjYWxlczo6c3F1aXNoKQoKICBnZ3NhdmUoCiAgICBwYXN0ZTAoIiMvVGVzc2VsbGF0aW9uX0tXX1ByZWNpc2lvbl8iLCBzdGF0LCAiLnBkZiIpLAogICAgcGxvdCA9IHByZWNpc2lvbl9wbG90LAogICAgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIKICApCiAgCiAgIyBFZmZpY2llbmN5IHBsb3Q6CiAgCiAgZWZmaWNpZW5jeV9wbG90IDwtIGdncGxvdChkZl90ZXNzLCBhZXMoeCA9IFN1YnNhbXBsZSwgeSA9IFBlYXJzb25fcmVsLCBmaWxsID0gU3Vic2FtcGxlKSkgKwogICAgZ2VvbV92aW9saW4odHJpbSA9IEZBTFNFKSArCiAgICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjIsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiU3RyYXRlZ3kgZWZmaWNpZW5jeSAoUGVhcnNvbiAvIFNhbXBsZSUpIC0iLCBzdGF0KSwgeSA9ICJSZWxhdGl2ZSBQZWFyc29uIikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiAgZ2dzYXZlKAogICAgcGFzdGUwKCIjL1Rlc3NlbGxhdGlvbl9LV19FZmZpY2llbmN5XyIsIHN0YXQsICIucGRmIiksCiAgICBwbG90ID0gZWZmaWNpZW5jeV9wbG90LAogICAgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIKICApCgogICMgS3J1c2thbOKAk1dhbGxpcyB0ZXN0cyBhbmQgcG9zdC1ob2MgY29tcGFyaXNpb25zOgogIGt3X3BlYXJzb24gPC0ga3J1c2thbF90ZXN0KFBlYXJzb25fQ29ycmVsYXRpb24gfiBTdWJzYW1wbGUsIGRhdGEgPSBkZl90ZXNzKQogIHBvc3Rob2NfcGVhcnNvbiA8LSBkdW5uX3Rlc3QoUGVhcnNvbl9Db3JyZWxhdGlvbiB+IFN1YnNhbXBsZSwgZGF0YSA9IGRmX3Rlc3MsIHAuYWRqdXN0Lm1ldGhvZCA9ICJCSCIpCiAgCiAga3dfZWZmIDwtIGtydXNrYWxfdGVzdChQZWFyc29uX3JlbCB+IFN1YnNhbXBsZSwgZGF0YSA9IGRmX3Rlc3MpCiAgcG9zdGhvY19lZmYgPC0gZHVubl90ZXN0KFBlYXJzb25fcmVsIH4gU3Vic2FtcGxlLCBkYXRhID0gZGZfdGVzcywgcC5hZGp1c3QubWV0aG9kID0gIkJIIikKICAKICAjIEV4cG9ydCByZXN1bHRzIHRvIEV4Y2VsCiAgd3JpdGVfeGxzeCgKICAgIGxpc3QoCiAgICAgIFN1bW1hcnlfU3RhdGlzdGljcyA9IHN1bW1hcnlfcHJlY2lzaW9uLAogICAgICBOb3JtYWxpdHlfVGVzdCA9IG5vcm1hbGl0eV9kZiwKICAgICAgS1dfUGVhcnNvbiA9IGFzLmRhdGEuZnJhbWUoa3dfcGVhcnNvbiksCiAgICAgIFBvc3RIb2NfUGVhcnNvbiA9IGFzLmRhdGEuZnJhbWUocG9zdGhvY19wZWFyc29uKSwKICAgICAgS1dfRWZmaWNpZW5jeSA9IGFzLmRhdGEuZnJhbWUoa3dfZWZmKSwKICAgICAgUG9zdEhvY19FZmZpY2llbmN5ID0gYXMuZGF0YS5mcmFtZShwb3N0aG9jX2VmZikKICAgICksCiAgICBwYXRoID0gcGFzdGUwKCIjL0tXX1Rlc3NlbGxhdGlvbl9TdHJhdGVnaWVzXyIsIHN0YXQsICIueGxzeCIpCiAgKQp9CgpgYGAKCiMgT0JKRUNUSVZFIDM6CgpTcGVjaWZpYyBvYmplY3RpdmUgMzogVG8gZXhwbG9yZSBob3cgdGhlIGludGVycGxheSBvZiBjYXRlZ29yaWNhbCAoZS5nLiwgbGFuZHNjYXBlLCB0aW1lLCBpbmRleCkgYW5kIGNvbnRpbnVvdXMgdmFyaWFibGVzIChlLmcuLCBzYW1wbGUgc2l6ZSwgcGVyZm9ybWFuY2UpIGV4cGxhaW5zIHRoZSBtdWx0aXZhcmlhdGUgc3RydWN0dXJlIHRoYXQgZGlmZmVyZW50aWF0ZXMgc3RyYXRpZmllZCBzdWJzYW1wbGluZyBzdHJhdGVnaWVzLgoKIyMgMy4xIEZBTUQgYW5hbHlzZXMKCkEgRmFjdG9yaWFsIEFuYWx5c2lzIG9mIE1peGVkIERhdGEgKEZBTUQpIGlzIGNvbmR1Y3RlZCB0byBleHBsb3JlIHRoZSBtdWx0aXZhcmlhdGUgc3RydWN0dXJlIG9mIHN0cmF0aWZpZWQgc3Vic2FtcGxpbmcgc3RyYXRlZ2llcyBieSBpbnRlZ3JhdGluZyBib3RoIGNhdGVnb3JpY2FsIGFuZCBjb250aW51b3VzIHZhcmlhYmxlcy4gVGhlIGRhdGFzZXQgd2FzIGZpbHRlcmVkIHRvIHJldGFpbiBvbmx5IHJlbGV2YW50IG9ic2VydmF0aW9ucyAoZS5nLiwgbWVkaWFuIHN0YXRpc3RpY3MgZnJvbSB0ZXNzZWxsYXRpb24tYmFzZWQgZGVzaWducykgYW5kIGluY2x1ZGVkIGtleSBsYW5kc2NhcGUsIHRlbXBvcmFsLCBhY291c3RpYywgYW5kIHBlcmZvcm1hbmNlIHZhcmlhYmxlcy4gVGhlIHZhcmlhYmxlIFN1YnNhbXBsZSwgd2hpY2ggZGVmaW5lcyB0aGUgc2FtcGxpbmcgc3RyYXRlZ3kgdW5kZXIgZXZhbHVhdGlvbiwgd2FzIHRyZWF0ZWQgYXMgYSBzdXBwbGVtZW50YXJ5IHF1YWxpdGF0aXZlIHZhcmlhYmxlIHRvIGF2b2lkIGluZmx1ZW5jaW5nIHRoZSBkaW1lbnNpb25hbCBjb25zdHJ1Y3Rpb24uCgpGQU1EIHdhcyBwZXJmb3JtZWQgdXNpbmcgdGhlIEZhY3RvTWluZVIgcGFja2FnZSwgZXh0cmFjdGluZyB0aGUgY29vcmRpbmF0ZXMgb2YgaW5kaXZpZHVhbHMsIHRoZSBjb250cmlidXRpb25zIG9mIHF1YW50aXRhdGl2ZSBhbmQgcXVhbGl0YXRpdmUgdmFyaWFibGVzLCBhbmQgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggZGltZW5zaW9uLiBSZXN1bHRzIHdlcmUgb3JnYW5pemVkIGludG8gc2VwYXJhdGUgRXhjZWwgc2hlZXRzIGZvciBzdWJzZXF1ZW50IHZpc3VhbGl6YXRpb24gYW5kIHN0YXRpc3RpY2FsIGFuYWx5c2lzLgoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KEZhY3RvTWluZVIpCmxpYnJhcnkoZmFjdG9leHRyYSkKbGlicmFyeShkcGx5cikKbGlicmFyeShvcGVueGxzeCkKCiMgTG9hZCBkYXRhc2V0IChyZXBsYWNlIHBhdGggYXMgbmVlZGVkKQpkYXRhIDwtIHJlYWRfZXhjZWwoIiMvREYxLTFfSW50ZXJwb2xhdGlvbnNfdmFyaW9ncmFtc19hbmRfZXJyb3JfZm9yX3N1YnNhbXBsZXMueGxzeCIpCgojIEZpbHRlciBvbmx5IHZhbGlkIHZhbHVlcyBhbmQgc2VsZWN0IHJlbGV2YW50IGNvbHVtbnMKZGF0YV9mYW1kIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShQZWFyc29uX0NvcnJlbGF0aW9uKSwgU3RhdGlzdGljID09ICJtZWRpYW4iLCBUeXBlID09ICJUZXNzZWxscyIpICU+JQogIHNlbGVjdChMb2NhbGl0eSwgRnJlcXVlbmN5X1JhbmdlLCBUaW1lX1BlcmlvZCwgSW5kZXgsIFN1YnNhbXBsZSwgU2FtcGxlX3BlcmNlbnQsIFBlYXJzb25fQ29ycmVsYXRpb24pCgojIENvbnZlcnQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRvIGZhY3RvcnMKZGF0YV9mYW1kIDwtIGRhdGFfZmFtZCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoTG9jYWxpdHksIEZyZXF1ZW5jeV9SYW5nZSwgVGltZV9QZXJpb2QsIEluZGV4LCBTdWJzYW1wbGUpLCBhcy5mYWN0b3IpKQoKIyBJZGVudGlmeSB0aGUgc3VwcGxlbWVudGFyeSBxdWFsaXRhdGl2ZSB2YXJpYWJsZSAoU3Vic2FtcGxlKQpzdXBwbGVtZW50YXJ5X3Zhcl9pbmRleCA8LSB3aGljaChjb2xuYW1lcyhkYXRhX2ZhbWQpID09ICJTdWJzYW1wbGUiKQoKIyBSdW4gRkFNRCB3aXRoIFN1YnNhbXBsZSBhcyBhIHN1cHBsZW1lbnRhcnkgdmFyaWFibGUKZmFtZF9yZXN1bHQgPC0gRkFNRChkYXRhX2ZhbWQsIAogICAgICAgICAgICAgICAgICAgIG5jcCA9IDUsIAogICAgICAgICAgICAgICAgICAgIHN1cC52YXIgPSBzdXBwbGVtZW50YXJ5X3Zhcl9pbmRleCwKICAgICAgICAgICAgICAgICAgICBncmFwaCA9IEZBTFNFKQoKIyBFeHRyYWN0IGNvb3JkaW5hdGVzIG9mIGluZGl2aWR1YWxzIGFuZCB2YXJpYWJsZXMKY29vcmRfaW5kIDwtIGFzLmRhdGEuZnJhbWUoZmFtZF9yZXN1bHQkaW5kJGNvb3JkKQpjb29yZF9pbmQkSUQgPC0gcm93bmFtZXMoY29vcmRfaW5kKQoKY29vcmRfcXVhbnRpIDwtIGFzLmRhdGEuZnJhbWUoZmFtZF9yZXN1bHQkcXVhbnRpLnZhciRjb29yZCkKY29vcmRfcXVhbnRpJFZhcmlhYmxlIDwtIHJvd25hbWVzKGNvb3JkX3F1YW50aSkKCmNvb3JkX3F1YWxpIDwtIGFzLmRhdGEuZnJhbWUoZmFtZF9yZXN1bHQkcXVhbGkudmFyJGNvb3JkKQpjb29yZF9xdWFsaSRDYXRlZ29yeSA8LSByb3duYW1lcyhjb29yZF9xdWFsaSkKCmVpZyA8LSBhcy5kYXRhLmZyYW1lKGZhbWRfcmVzdWx0JGVpZykKY29sbmFtZXMoZWlnKSA8LSBjKCJEaW1lbnNpb24iLCAiVmFyaWFuY2UgKCUpIiwgIkN1bXVsYXRpdmUgVmFyaWFuY2UgKCUpIikKCiMgU2F2ZSByZXN1bHRzIHRvIEV4Y2VsCndiIDwtIGNyZWF0ZVdvcmtib29rKCkKYWRkV29ya3NoZWV0KHdiLCAiSW5kaXZpZHVhbF9Db29yZGluYXRlcyIpCmFkZFdvcmtzaGVldCh3YiwgIlF1YW50aXRhdGl2ZV9WYXJpYWJsZXMiKQphZGRXb3Jrc2hlZXQod2IsICJRdWFsaXRhdGl2ZV9WYXJpYWJsZXMiKQphZGRXb3Jrc2hlZXQod2IsICJFeHBsYWluZWRfVmFyaWFuY2UiKQoKd3JpdGVEYXRhKHdiLCBzaGVldCA9ICJJbmRpdmlkdWFsX0Nvb3JkaW5hdGVzIiwgY29vcmRfaW5kKQp3cml0ZURhdGEod2IsIHNoZWV0ID0gIlF1YW50aXRhdGl2ZV9WYXJpYWJsZXMiLCBjb29yZF9xdWFudGkpCndyaXRlRGF0YSh3Yiwgc2hlZXQgPSAiUXVhbGl0YXRpdmVfVmFyaWFibGVzIiwgY29vcmRfcXVhbGkpCndyaXRlRGF0YSh3Yiwgc2hlZXQgPSAiRXhwbGFpbmVkX1ZhcmlhbmNlIiwgZWlnKQoKc2F2ZVdvcmtib29rKHdiLCAiIy9GQU1EX3Jlc3VsdHNfZXhwb3J0Lnhsc3giLCBvdmVyd3JpdGUgPSBUUlVFKQoKYGBgCgojIyAzLjIgR3JhcGhpY2FsIGFic3RyYWN0IHBsb3RzIGZvciBGQU1ECgpUaGlzIHNjcmlwdCBnZW5lcmF0ZXMgYSB2aXN1YWwgc3VtbWFyeSBvZiB0aGUgRmFjdG9yaWFsIEFuYWx5c2lzIG9mIE1peGVkIERhdGEgKEZBTUQpIHJlc3VsdHMuIEl0IGluY2x1ZGVzIGEgc2NyZWUgcGxvdCBzaG93aW5nIHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBkaW1lbnNpb24sIGFsb25nIHdpdGggYmFyIHBsb3RzIGRpc3BsYXlpbmcgdGhlIHRvcCBjb250cmlidXRpbmcgdmFyaWFibGVzIHRvIERpbWVuc2lvbnMgMSB0aHJvdWdoIDQuIEFsbCBwbG90cyBhcmUgc3R5bGVkIGNvbnNpc3RlbnRseSB1c2luZyBhIG1pbmltYWwgdGhlbWUgYW5kIGFycmFuZ2VkIHVzaW5nIHRoZSBwYXRjaHdvcmsgcGFja2FnZSBpbnRvIGEgc2luZ2xlIGNvbWJpbmVkIGZpZ3VyZS4gVGhlIGZpbmFsIG91dHB1dCBpcyBzYXZlZCBhcyBhIGhpZ2gtcmVzb2x1dGlvbiBQREYgZm9yIHB1YmxpY2F0aW9uIG9yIHJlcG9ydGluZyBwdXJwb3Nlcy4KCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCiMgRW5zdXJlICdwYXRjaHdvcmsnIGlzIGluc3RhbGxlZDogaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KHBhdGNod29yaykgICAjIEZvciBjb21iaW5pbmcgZ2dwbG90LWJhc2VkIGNoYXJ0cwpsaWJyYXJ5KGdncGxvdDIpCgojIEFzc3VtZXMgJ2ZhbWRfcmVzdWx0JyBhbHJlYWR5IGV4aXN0cyBhbmQgaXMgdmFsaWQKIyAoVGhpcyBpcyB0aGUgcmVzdWx0IG9iamVjdCBmcm9tIG91ciBwcmV2b3VzbHkgY29uc3RydWN0ZWQgRkFNRCBhbmFseXNpcykKIyBDcmVhdGUgYW5kIGN1c3RvbWl6ZSBpbmRpdmlkdWFsIHBsb3RzCiMgU2NyZWUgcGxvdCB3aXRoIHRoZW1lIGFuZCB5LWF4aXMgdmlldyBhZGp1c3RtZW50CnBsb3Rfc2NyZWUgPC0gZnZpel9zY3JlZXBsb3QoZmFtZF9yZXN1bHQsIGFkZGxhYmVscyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkpICsKICBnZ3RpdGxlKCJTY3JlZSBQbG90IChFeHBsYWluZWQgVmFyaWFuY2UgYnkgRGltZW5zaW9uKSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMTcpKSAgIyBBZGp1c3QgdGhpcyB1cHBlciBsaW1pdCBpZiBuZWVkZWQKCiMgQ29udHJpYnV0aW9uIHBsb3RzIGZvciBkaW1lbnNpb25zIDEgdG8gNApwbG90X2NvbnRyaWJfZGltMSA8LSBmdml6X2NvbnRyaWIoZmFtZF9yZXN1bHQsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMSwgdG9wID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKSArCiAgZ2d0aXRsZSgiQ29udHJpYnV0aW9uIHRvIERpbS4xIChUb3AgMTApIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90X2NvbnRyaWJfZGltMiA8LSBmdml6X2NvbnRyaWIoZmFtZF9yZXN1bHQsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMiwgdG9wID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKSArCiAgZ2d0aXRsZSgiQ29udHJpYnV0aW9uIHRvIERpbS4yIChUb3AgMTApIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90X2NvbnRyaWJfZGltMyA8LSBmdml6X2NvbnRyaWIoZmFtZF9yZXN1bHQsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMywgdG9wID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKSArCiAgZ2d0aXRsZSgiQ29udHJpYnV0aW9uIHRvIERpbS4zIChUb3AgMTApIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90X2NvbnRyaWJfZGltNCA8LSBmdml6X2NvbnRyaWIoZmFtZF9yZXN1bHQsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gNCwgdG9wID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKSArCiAgZ2d0aXRsZSgiQ29udHJpYnV0aW9uIHRvIERpbS40IChUb3AgMTApIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIENvbWJpbmUgcGxvdHMgdXNpbmcgcGF0Y2h3b3JrCmNvbWJpbmVkX3Bsb3QgPC0gcGxvdF9zY3JlZSAvCiAgKHBsb3RfY29udHJpYl9kaW0xICsgcGxvdF9jb250cmliX2RpbTIpIC8KICAocGxvdF9jb250cmliX2RpbTMgKyBwbG90X2NvbnRyaWJfZGltNCkKCiMgQWRkIGdsb2JhbCB0aXRsZSB0byB0aGUgZnVsbCBsYXlvdXQKY29tYmluZWRfcGxvdCA8LSBjb21iaW5lZF9wbG90ICsgCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIiAgICAgIEZBTUQgLSBNRURJQU4iKQoKIyBEaXNwbGF5IGNvbWJpbmVkIHBsb3QKcHJpbnQoY29tYmluZWRfcGxvdCkKCiMgU2F2ZSB0aGUgY29tYmluZWQgcGxvdCBhcyBQREYgKHVwZGF0ZSBwYXRoIGFjY29yZGluZ2x5KQpnZ3NhdmUoCiAgZmlsZW5hbWUgPSAiIy9GQU1EX3N1bW1hcnlfcGxvdF9NRURJQU4ucGRmIiwKICBwbG90ID0gY29tYmluZWRfcGxvdCwKICBkZXZpY2UgPSAicGRmIiwKICB3aWR0aCA9IDgsCiAgaGVpZ2h0ID0gMTAsCiAgdW5pdHMgPSAiaW4iCikKCmBgYAoKIyMgMy4zIFZhcmlhYmxlcyBwcm9qZWN0aW9uIGFuZCBpbmRpdmlkdWFscyBwbG90CgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShGYWN0b01pbmVSKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCgojIExvYWQgZGF0YXNldCAoYWRqdXN0IHBhdGggYWNjb3JkaW5nbHkpCmRhdGEgPC0gcmVhZF9leGNlbCgiIy9ERjEtMV9JbnRlcnBvbGF0aW9uc192YXJpb2dyYW1zX2FuZF9lcnJvcl9mb3Jfc3Vic2FtcGxlcy54bHN4IikKCiMgUHJlcGFyZSB2YXJpYWJsZXMgZm9yIEZBTUQKZGF0YV9mYW1kIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShQZWFyc29uX0NvcnJlbGF0aW9uKSwgU3RhdGlzdGljID09ICJtZWRpYW4iLCBUeXBlID09ICJUZXNzZWxscyIpICU+JQogIHNlbGVjdChMb2NhbGl0eSwgRnJlcXVlbmN5X1JhbmdlLCBUaW1lX1BlcmlvZCwgSW5kZXgsIFN1YnNhbXBsZSwgU2FtcGxlX3BlcmNlbnQsIFBlYXJzb25fQ29ycmVsYXRpb24pICU+JQogIG11dGF0ZShhY3Jvc3MoYyhMb2NhbGl0eSwgRnJlcXVlbmN5X1JhbmdlLCBUaW1lX1BlcmlvZCwgSW5kZXgsIFN1YnNhbXBsZSksIGFzLmZhY3RvcikpCgojIFJ1biBGQU1EIChGYWN0b3JpYWwgQW5hbHlzaXMgb2YgTWl4ZWQgRGF0YSkKZmFtZF9yZXN1bHQgPC0gRkFNRChkYXRhX2ZhbWQsIG5jcCA9IDUsIGdyYXBoID0gRkFMU0UpCgojIFZhcmlhYmxlIHByb2plY3Rpb24gcGxvdHMgKHJlcGVsID0gVFJVRSBmb3IgbGFiZWwgY2xhcml0eSkKcGxvdF92YXJfMTIgPC0gZnZpel9mYW1kX3ZhcihmYW1kX3Jlc3VsdCwgYXhlcyA9IGMoMSwgMiksIHJlcGVsID0gVFJVRSkgKyAKICBnZ3RpdGxlKCJWYXJpYWJsZXM6IERpbSAxIHZzIERpbSAyIikKcGxvdF92YXJfMjMgPC0gZnZpel9mYW1kX3ZhcihmYW1kX3Jlc3VsdCwgYXhlcyA9IGMoMiwgMyksIHJlcGVsID0gVFJVRSkgKyAKICBnZ3RpdGxlKCJWYXJpYWJsZXM6IERpbSAyIHZzIERpbSAzIikKcGxvdF92YXJfMTMgPC0gZnZpel9mYW1kX3ZhcihmYW1kX3Jlc3VsdCwgYXhlcyA9IGMoMSwgMyksIHJlcGVsID0gVFJVRSkgKyAKICBnZ3RpdGxlKCJWYXJpYWJsZXM6IERpbSAxIHZzIERpbSAzIikKIyBJbmRpdmlkdWFsIHByb2plY3Rpb24gcGxvdHMgKGNsZWFuIHZlcnNpb24gd2l0aG91dCBsYWJlbHMsIHdpdGggZWxsaXBzZXMgYnkgU3Vic2FtcGxlKQpwbG90X2luZF8xMiA8LSBmdml6X2ZhbWRfaW5kKGZhbWRfcmVzdWx0LCBheGVzID0gYygxLCAyKSwgaGFiaWxsYWdlID0gIlN1YnNhbXBsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwgbGFiZWwgPSAibm9uZSIpICsgCiAgZ2d0aXRsZSgiSW5kaXZpZHVhbHM6IERpbSAxIHZzIERpbSAyIikKcGxvdF9pbmRfMjMgPC0gZnZpel9mYW1kX2luZChmYW1kX3Jlc3VsdCwgYXhlcyA9IGMoMiwgMyksIGhhYmlsbGFnZSA9ICJTdWJzYW1wbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsIGxhYmVsID0gIm5vbmUiKSArIAogIGdndGl0bGUoIkluZGl2aWR1YWxzOiBEaW0gMiB2cyBEaW0gMyIpCnBsb3RfaW5kXzEzIDwtIGZ2aXpfZmFtZF9pbmQoZmFtZF9yZXN1bHQsIGF4ZXMgPSBjKDEsIDMpLCBoYWJpbGxhZ2UgPSAiU3Vic2FtcGxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLCBsYWJlbCA9ICJub25lIikgKyAKICBnZ3RpdGxlKCJJbmRpdmlkdWFsczogRGltIDEgdnMgRGltIDMiKQoKIyBDb21iaW5lIGFsbCBwbG90cyBpbiBhIDItY29sdW1uIMOXIDMtcm93IGxheW91dApjb21iaW5lZF9wbG90IDwtIChwbG90X3Zhcl8xMiB8IHBsb3RfaW5kXzEyKSAvCiAgICAgICAgICAgICAgICAgKHBsb3RfdmFyXzIzIHwgcGxvdF9pbmRfMjMpIC8KICAgICAgICAgICAgICAgICAocGxvdF92YXJfMTMgfCBwbG90X2luZF8xMykgKwogICAgICAgICAgICAgICAgIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJGQU1EIFByb2plY3Rpb25zIOKAkyBWYXJpYWJsZXMgJiBJbmRpdmlkdWFscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpKSkKIyBEaXNwbGF5IHRoZSBjb21iaW5lZCBwbG90CnByaW50KGNvbWJpbmVkX3Bsb3QpCgojIFNhdmUgdGhlIHBsb3QgdG8gUERGICh1cGRhdGUgcGF0aCBhcyBuZWVkZWQpCmdnc2F2ZSgKICBmaWxlbmFtZSA9ICIjL0ZBTURfdmFyaWFibGVzX2luZGl2aWR1YWxzX2NsZWFuX01FRElBTi5wZGYiLAogIHBsb3QgPSBjb21iaW5lZF9wbG90LAogIGRldmljZSA9ICJwZGYiLAogIHdpZHRoID0gMTIsCiAgaGVpZ2h0ID0gMTQsCiAgdW5pdHMgPSAiaW4iCikKCmBgYAoKIyMgMy40IEtSVVNLQUxMIFRFU1QKClRoaXMgZ3JhcGggcHJlc2VudHMgdGhlIHJlc3VsdHMgb2YgYSBzdGF0aXN0aWNhbCBhbmFseXNpcyAoS3J1c2thbC1XYWxsaXMgKyBwb3N0LWhvYyBEdW5uKSBhcHBsaWVkIHRvIHRoZSBjb29yZGluYXRlcyBvZiBkaW1lbnNpb24gMyAoRGltLjMpIG9mIHRoZSBGQU1EIGFuYWx5c2lzLCB3aXRoIHRoZSBhaW0gb2YgY29tcGFyaW5nIHRoZSBzdHJhdGlmaWVkIHNhbXBsaW5nIG1ldGhvZHMgKFN1YnNhbXBsZTogYmFzaW5zLCBoYWxmYmFzaW5zLCBTTElDKS4KCmBgYHtyfQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KEZhY3RvTWluZVIpCmxpYnJhcnkoZmFjdG9leHRyYSkKbGlicmFyeShkcGx5cikKbGlicmFyeShyc3RhdGl4KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShtdWx0Y29tcFZpZXcpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHdyaXRleGwpCgojIExvYWQgYW5kIHByZXBhcmUgZGF0YQpkYXRhIDwtIHJlYWRfZXhjZWwoIiMvREYxLTFfSW50ZXJwb2xhdGlvbnNfdmFyaW9ncmFtc19hbmRfZXJyb3JfZm9yX3N1YnNhbXBsZXMueGxzeCIpCgpkYXRhX2ZhbWQgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKFBlYXJzb25fQ29ycmVsYXRpb24pLCBTdGF0aXN0aWMgPT0gIm1lZGlhbiIsIFR5cGUgPT0gIlRlc3NlbGxzIikgJT4lCiAgc2VsZWN0KExvY2FsaXR5LCBGcmVxdWVuY3lfUmFuZ2UsIFRpbWVfUGVyaW9kLCBJbmRleCwgU3Vic2FtcGxlLCBTYW1wbGVfcGVyY2VudCwgUGVhcnNvbl9Db3JyZWxhdGlvbikgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKExvY2FsaXR5LCBGcmVxdWVuY3lfUmFuZ2UsIFRpbWVfUGVyaW9kLCBJbmRleCwgU3Vic2FtcGxlKSwgYXMuZmFjdG9yKSkKCiMgUnVuIEZBTUQKZmFtZF9yZXN1bHQgPC0gRkFNRChkYXRhX2ZhbWQsIG5jcCA9IDUsIGdyYXBoID0gRkFMU0UpCgppbmRfY29vcmQgPC0gYXMuZGF0YS5mcmFtZShmYW1kX3Jlc3VsdCRpbmQkY29vcmRbLCAxOjRdKSAgIyBLZWVwIG9ubHkgZmlyc3QgZm91ciBkaW1lbnNpb25zCmluZF9jb29yZCRTdWJzYW1wbGUgPC0gZGF0YV9mYW1kJFN1YnNhbXBsZQoKIyBEZWZpbmUgYSByZXVzYWJsZSBmdW5jdGlvbiBmb3IgZWFjaCBkaW1lbnNpb24ncyBhbmFseXNpcwprcnVza2FsX2R1bm5fcGxvdCA8LSBmdW5jdGlvbihkZiwgZGltX251bSkgewogIGRpbV9jb2wgPC0gcGFzdGUwKCJEaW0uIiwgZGltX251bSkKICAKICBrdyA8LSBrcnVza2FsX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoZGltX2NvbCwgIiB+IFN1YnNhbXBsZSIpKSwgZGF0YSA9IGRmKQogIGR1bm4gPC0gZHVubl90ZXN0KGFzLmZvcm11bGEocGFzdGUwKGRpbV9jb2wsICIgfiBTdWJzYW1wbGUiKSksIGRhdGEgPSBkZiwgcC5hZGp1c3QubWV0aG9kID0gIkJIIikKCiAgbGV0dGVyc19kZiA8LSBOVUxMCiAgaWYgKGt3JHAgPCAwLjA1KSB7CiAgICBncm91cHMgPC0gbGV2ZWxzKGRmJFN1YnNhbXBsZSkKICAgIHBtYXQgPC0gbWF0cml4KDEsIGxlbmd0aChncm91cHMpLCBsZW5ndGgoZ3JvdXBzKSwgZGltbmFtZXMgPSBsaXN0KGdyb3VwcywgZ3JvdXBzKSkKICAgIGRpYWcocG1hdCkgPC0gMAogICAgZm9yIChpIGluIDE6bnJvdyhkdW5uKSkgewogICAgICBwbWF0W2R1bm4kZ3JvdXAxW2ldLCBkdW5uJGdyb3VwMltpXV0gPC0gZHVubiRwLmFkaltpXQogICAgICBwbWF0W2R1bm4kZ3JvdXAyW2ldLCBkdW5uJGdyb3VwMVtpXV0gPC0gZHVubiRwLmFkaltpXQogICAgfQogICAgc2lnbmlmX21hdHJpeCA8LSBwbWF0IDwgMC4wNQogICAgZGlhZyhzaWduaWZfbWF0cml4KSA8LSBGQUxTRQogICAgbGV0dGVycyA8LSBtdWx0Y29tcExldHRlcnMoc2lnbmlmX21hdHJpeCkkTGV0dGVycwogICAgbGV0dGVyc19kZiA8LSBlbmZyYW1lKGxldHRlcnMsIG5hbWUgPSAiU3Vic2FtcGxlIiwgdmFsdWUgPSAiTGV0dGVyIikKICAgIAogICAgcG9zIDwtIGRmICU+JQogICAgICBncm91cF9ieShTdWJzYW1wbGUpICU+JQogICAgICBzdW1tYXJpc2UoCiAgICAgICAgcTMgPSBxdWFudGlsZSguZGF0YVtbZGltX2NvbF1dLCAwLjc1KSwKICAgICAgICBpcXIgPSBJUVIoLmRhdGFbW2RpbV9jb2xdXSksCiAgICAgICAgdXBwZXIgPSBxMyArIDEuNSAqIGlxciwKICAgICAgICBtYXggPSBtYXgoLmRhdGFbW2RpbV9jb2xdXSwgbmEucm0gPSBUUlVFKSwKICAgICAgICB5LnBvc2l0aW9uID0gbWF4KHVwcGVyLCBtYXgpICsgMC4xNQogICAgICApCiAgICAKICAgIGxldHRlcnNfZGYgPC0gbGVmdF9qb2luKGxldHRlcnNfZGYsIHBvcywgYnkgPSAiU3Vic2FtcGxlIikKICB9CgogIHltYXggPC0gbWF4KGRmW1tkaW1fY29sXV0sIG5hLnJtID0gVFJVRSkKICBicmFja2V0X3kgPC0gaWYgKCFpcy5udWxsKGxldHRlcnNfZGYpKSBtYXgobGV0dGVyc19kZiR5LnBvc2l0aW9uLCBuYS5ybSA9IFRSVUUpICsgMC4xIGVsc2UgeW1heCArIDAuMgoKICBkdW5uX3Bsb3QgPC0gZHVubiAlPiUKICAgIGZpbHRlcihwLmFkaiA8PSAwLjA1KSAlPiUKICAgIGFycmFuZ2UoZ3JvdXAxLCBncm91cDIpICU+JQogICAgbXV0YXRlKHkucG9zaXRpb24gPSBzZXEoYnJhY2tldF95LCBieSA9IDAuMTUsIGxlbmd0aC5vdXQgPSBuKCkpKQoKICBwbG90IDwtIGdnYm94cGxvdChkZiwgeCA9ICJTdWJzYW1wbGUiLCB5ID0gZGltX2NvbCwgZmlsbCA9ICJTdWJzYW1wbGUiLCBwYWxldHRlID0gIlNldDIiKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHBhc3RlKCJLcnVza2FsLVdhbGxpcyBieSBTdWJzYW1wbGluZyBTdHJhdGVneSAtIERpbWVuc2lvbiIsIGRpbV9udW0pLAogICAgICBzdWJ0aXRsZSA9IGdldF90ZXN0X2xhYmVsKGt3LCBkZXRhaWxlZCA9IFRSVUUpLAogICAgICB5ID0gcGFzdGUoIkZBTUQgQ29vcmRpbmF0ZSAtIERpbSIsIGRpbV9udW0pLAogICAgICB4ID0gIlN1YnNhbXBsaW5nIFN0cmF0ZWd5IgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgogIGlmICghaXMubnVsbChsZXR0ZXJzX2RmKSkgewogICAgcGxvdCA8LSBwbG90ICsgZ2VvbV90ZXh0KGRhdGEgPSBsZXR0ZXJzX2RmLCBhZXMoeCA9IFN1YnNhbXBsZSwgeSA9IHkucG9zaXRpb24sIGxhYmVsID0gTGV0dGVyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaXplID0gNSwgdmp1c3QgPSAtMC41KQogIH0KCiAgaWYgKG5yb3coZHVubl9wbG90KSA+IDApIHsKICAgIHBsb3QgPC0gcGxvdCArIHN0YXRfcHZhbHVlX21hbnVhbChkdW5uX3Bsb3QsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsIHRpcC5sZW5ndGggPSAwLjAxKQogIH0gZWxzZSBpZiAoa3ckcCA8IDAuMDUpIHsKICAgIHBsb3QgPC0gcGxvdCArIGxhYnMoY2FwdGlvbiA9ICJLcnVza2FsLVdhbGxpcyB3YXMgc2lnbmlmaWNhbnQsIGJ1dCBubyBwYWlyd2lzZSBkaWZmZXJlbmNlcyBkZXRlY3RlZC4iKQogIH0KCiAgcmV0dXJuKHBsb3QpCn0KCiMgR2VuZXJhdGUgcGxvdHMgZm9yIHRoZSBmaXJzdCBmb3VyIGRpbWVuc2lvbnMKcGxvdF9kaW0xIDwtIGtydXNrYWxfZHVubl9wbG90KGluZF9jb29yZCwgMSkKcGxvdF9kaW0yIDwtIGtydXNrYWxfZHVubl9wbG90KGluZF9jb29yZCwgMikKcGxvdF9kaW0zIDwtIGtydXNrYWxfZHVubl9wbG90KGluZF9jb29yZCwgMykKcGxvdF9kaW00IDwtIGtydXNrYWxfZHVubl9wbG90KGluZF9jb29yZCwgNCkKCiMgQ29tYmluZSBhbGwgcGxvdHMgaW50byBhIGdyaWQgbGF5b3V0CmZpbmFsX3Bsb3QgPC0gKHBsb3RfZGltMSB8IHBsb3RfZGltMikgLyAocGxvdF9kaW0zIHwgcGxvdF9kaW00KSArCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIktydXNrYWzigJNXYWxsaXMgKyBEdW5uIFRlc3RzIOKAkyBGQU1EIERpbWVuc2lvbnMiKQoKIyBTYXZlIGZpbmFsIHBsb3QgdG8gUERGCmdnc2F2ZSgKICBmaWxlbmFtZSA9ICIjL0ZBTURfS1dfRHVubl9SZXN1bHRzLnBkZiIsCiAgcGxvdCA9IGZpbmFsX3Bsb3QsCiAgZGV2aWNlID0gInBkZiIsCiAgd2lkdGggPSAxNCwKICBoZWlnaHQgPSAxMiwKICB1bml0cyA9ICJpbiIKKQoKIyBFeHBvcnQgcmVzdWx0cyBmb3IgZWFjaCBkaW1lbnNpb24gdG8gRXhjZWwKbGlicmFyeShvcGVueGxzeCkKCndiIDwtIGNyZWF0ZVdvcmtib29rKCkKCmZvciAoZGltX251bSBpbiAxOjQpIHsKICBkaW1fY29sIDwtIHBhc3RlMCgiRGltLiIsIGRpbV9udW0pCgogIGt3X3Jlc3VsdCA8LSBrcnVza2FsX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoZGltX2NvbCwgIiB+IFN1YnNhbXBsZSIpKSwgZGF0YSA9IGluZF9jb29yZCkKICBkdW5uX3Jlc3VsdCA8LSBkdW5uX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoZGltX2NvbCwgIiB+IFN1YnNhbXBsZSIpKSwgZGF0YSA9IGluZF9jb29yZCwgcC5hZGp1c3QubWV0aG9kID0gIkJIIikKCiAgZ3JvdXBzIDwtIGxldmVscyhpbmRfY29vcmQkU3Vic2FtcGxlKQogIHBtYXQgPC0gbWF0cml4KDEsIGxlbmd0aChncm91cHMpLCBsZW5ndGgoZ3JvdXBzKSwgZGltbmFtZXMgPSBsaXN0KGdyb3VwcywgZ3JvdXBzKSkKICBkaWFnKHBtYXQpIDwtIDAKCiAgZm9yIChpIGluIDE6bnJvdyhkdW5uX3Jlc3VsdCkpIHsKICAgIHBtYXRbZHVubl9yZXN1bHQkZ3JvdXAxW2ldLCBkdW5uX3Jlc3VsdCRncm91cDJbaV1dIDwtIGR1bm5fcmVzdWx0JHAuYWRqW2ldCiAgICBwbWF0W2R1bm5fcmVzdWx0JGdyb3VwMltpXSwgZHVubl9yZXN1bHQkZ3JvdXAxW2ldXSA8LSBkdW5uX3Jlc3VsdCRwLmFkaltpXQogIH0KCiAgc2lnbmlmX21hdHJpeCA8LSBwbWF0IDwgMC4wNQogIGRpYWcoc2lnbmlmX21hdHJpeCkgPC0gRkFMU0UKICBsZXR0ZXJzIDwtIG11bHRjb21wTGV0dGVycyhzaWduaWZfbWF0cml4KSRMZXR0ZXJzCiAgbGV0dGVyc19kZiA8LSBlbmZyYW1lKGxldHRlcnMsIG5hbWUgPSAiU3Vic2FtcGxlIiwgdmFsdWUgPSAiU2lnbmlmaWNhbmNlX0xldHRlciIpCgogIHNoZWV0X25hbWUgPC0gcGFzdGUwKCJEaW1lbnNpb25fIiwgZGltX251bSkKICBpZiAoc2hlZXRfbmFtZSAlaW4lIG5hbWVzKHdiKSkgcmVtb3ZlV29ya3NoZWV0KHdiLCBzaGVldCA9IHNoZWV0X25hbWUpCgogIGFkZFdvcmtzaGVldCh3Yiwgc2hlZXRfbmFtZSkKICB3cml0ZURhdGEod2IsIHNoZWV0ID0gc2hlZXRfbmFtZSwgeCA9IGt3X3Jlc3VsdCwgc3RhcnRDb2wgPSAxLCBzdGFydFJvdyA9IDEpCiAgd3JpdGVEYXRhKHdiLCBzaGVldCA9IHNoZWV0X25hbWUsIHggPSBkdW5uX3Jlc3VsdCwgc3RhcnRDb2wgPSAxLCBzdGFydFJvdyA9IDUpCiAgd3JpdGVEYXRhKHdiLCBzaGVldCA9IHNoZWV0X25hbWUsIHggPSBsZXR0ZXJzX2RmLCBzdGFydENvbCA9IDEsIHN0YXJ0Um93ID0gbnJvdyhkdW5uX3Jlc3VsdCkgKyA4KQp9CgpzYXZlV29ya2Jvb2sod2IsIGZpbGUgPSAiIy9GQU1EX0tXX0R1bm5fcmVzdWx0c19leHBvcnQueGxzeCIsIG92ZXJ3cml0ZSA9IFRSVUUpCgoKYGBgCgojIyAzLjUgSEVBVE1BUAoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3RleHQpICAjIE9wY2lvbmFsOiBwYXJhIHRleHRvIGVucmlxdWVjaWRvCgoKbGV0cmFzX2RmIDwtIHRyaWJibGUoCiAgflNUQVRJU1RJQywgfkRJTUVOU0lPTiwgflN1YnNhbXBsZSwgflNpZ25pZmljYW5jZV9MZXR0ZXIsCiAgIm1lZGlhbiIsIkRpbS4xIiwgImJhc2lucyIsICAgICAiYSIsCiAgIm1lZGlhbiIsIkRpbS4xIiwgImhhbGZiYXNpbnMiLCAiYiIsCiAgIm1lZGlhbiIsIkRpbS4xIiwgIkxhbmRjb3ZlciIsICAiYyIsCiAgIm1lZGlhbiIsIkRpbS4xIiwgIlNMSUMiLCAgICAgICAiZCIsCiAgIm1lZGlhbiIsIkRpbS4yIiwgImJhc2lucyIsICAgICAiYSIsCiAgIm1lZGlhbiIsIkRpbS4yIiwgImhhbGZiYXNpbnMiLCAiYiIsCiAgIm1lZGlhbiIsIkRpbS4yIiwgIkxhbmRjb3ZlciIsICAiYyIsCiAgIm1lZGlhbiIsIkRpbS4yIiwgIlNMSUMiLCAgICAgICAiYWIiLAogICJtZWRpYW4iLCJEaW0uMyIsICJiYXNpbnMiLCAgICAgImEiLAogICJtZWRpYW4iLCJEaW0uMyIsICJoYWxmYmFzaW5zIiwgImIiLAogICJtZWRpYW4iLCJEaW0uMyIsICJMYW5kY292ZXIiLCAgImIiLAogICJtZWRpYW4iLCJEaW0uMyIsICJTTElDIiwgICAgICAgImIiLAogICJtZWRpYW4iLCJEaW0uNCIsICJiYXNpbnMiLCAgICAgImEiLAogICJtZWRpYW4iLCJEaW0uNCIsICJoYWxmYmFzaW5zIiwgImIiLAogICJtZWRpYW4iLCJEaW0uNCIsICJMYW5kY292ZXIiLCAgImMiLAogICJtZWRpYW4iLCJEaW0uNCIsICJTTElDIiwgICAgICAgImMiCikKCiMgUGl2b3RlYXIgYSBmb3JtYXRvIGFuY2hvCmxldHJhc19tYXRyaXggPC0gbGV0cmFzX2RmICU+JQogIHVuaXRlKCJEaW1lbnNpb25fVHlwZSIsIFNUQVRJU1RJQywgRElNRU5TSU9OLCBzZXAgPSAiXyIpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBEaW1lbnNpb25fVHlwZSwgdmFsdWVzX2Zyb20gPSBTaWduaWZpY2FuY2VfTGV0dGVyKQoKIyBDb252ZXJ0aXIgZW4gZGF0YS5mcmFtZSBwYXJhIGdncGxvdApsZXRyYXNfbG9uZyA8LSBsZXRyYXNfbWF0cml4ICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLVN1YnNhbXBsZSwgbmFtZXNfdG8gPSAiRGltZW5zaW9uIiwgdmFsdWVzX3RvID0gIkxldHRlciIpCgojIE9yZGVuYXIgcGFyYSBlc3TDqXRpY2EKbGV0cmFzX2xvbmckU3Vic2FtcGxlIDwtIGZhY3RvcihsZXRyYXNfbG9uZyRTdWJzYW1wbGUsIGxldmVscyA9IGMoImJhc2lucyIsICJoYWxmYmFzaW5zIiwgIkxhbmRjb3ZlciIsICJTTElDIikpCmxldHJhc19sb25nJERpbWVuc2lvbiA8LSBmYWN0b3IobGV0cmFzX2xvbmckRGltZW5zaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIm1lYW5fRGltLjEiLCAibWVhbl9EaW0uMiIsICJtZWFuX0RpbS4zIiwgIm1lYW5fRGltLjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1lZGlhbl9EaW0uMSIsICJtZWRpYW5fRGltLjIiLCAibWVkaWFuX0RpbS4zIiwgIm1lZGlhbl9EaW0uNCIpKQoKIyBIZWF0bWFwCmdncGxvdChsZXRyYXNfbG9uZywgYWVzKHggPSBEaW1lbnNpb24sIHkgPSBTdWJzYW1wbGUsIGZpbGwgPSBMZXR0ZXIpKSArCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBMZXR0ZXIpLCBzaXplID0gNSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJwbGFzbWEiLCBkaXJlY3Rpb24gPSAtMSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJTaWduaWZpY2FuY2UgTGV0dGVyIEdyb3VwaW5ncyBieSBGQU1EIERpbWVuc2lvbiBhbmQgU3RyYXRlZ3kiLAogICAgeCA9ICJGQU1EIERpbWVuc2lvbiIsIHkgPSAiU3Vic2FtcGxpbmcgU3RyYXRlZ3kiLCBmaWxsID0gIkxldHRlciIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCmdnc2F2ZSgKICBmaWxlbmFtZSA9ICIvaG9tZS92bWFydGluZXphcmlhcy9Ecm9wYm94L0RvY3RvcmFkb19QZXJzb25hbF9Gb2xkZXIvVGhlc2lzQW5hbHlzZXMvUFJPVklTSU9OQUxFU19QQVBFUlMvT0JKRUNUSVZFMy9WMi8zLjUtRkFNRF9oZWF0bWFwX2xldHRlcnMucGRmIiwKICBwbG90ID0gbGFzdF9wbG90KCksICAjIG8gZ3VhcmRhIHR1IHBsb3QgZW4gdW4gb2JqZXRvOiBwIDwtIGdncGxvdCguLi4pIHkgcG9uIHBsb3QgPSBwCiAgd2lkdGggPSAxMCwKICBoZWlnaHQgPSA2LAogIHVuaXRzID0gImluIiwKICBkZXZpY2UgPSAicGRmIgopCgoKYGBgCgojIDQgT0JKRUNUSVZFIDQ6IExBTkRTQ0FQRSBSRVBSRVNFTlRBVElPTgoKU3BlY2lmaWMgb2JqZWN0aXZlIDQ6IERldGVybWluZSB0aGUgaW5mbHVlbmNlIG9mIGxhbmRzY2FwZSBoZXRlcm9nZW5laXR5IG9uIHRoZSBwZXJmb3JtYW5jZSBhbmQgcmVwcmVzZW50YXRpdmVuZXNzIG9mIHNvdW5kc2NhcGUgaW5mb3JtYXRpb24gb2J0YWluZWQgdXNpbmcgdGVzc2VsbGF0aW9uLWJhc2VkIHNhbXBsaW5nIHN0cmF0ZWdpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KG9wZW54bHN4KSAgIyBGb3IgZXhwb3J0aW5nIHRvIEV4Y2VsCgojIExvYWQgRXhjZWwgZmlsZQpkZiA8LSByZWFkX2V4Y2VsKCIjL0RGM19TdWJzYW1wbGluZ19IZXRlcm9nZW5laXR5X0NvbXBhcmlzb24ueGxzeCIpCgojIEZpbHRlciB2YWxpZCB2YWx1ZXMKZGZfZmlsdGVyZWQgPC0gZGYgJT4lIGZpbHRlcighaXMubmEoTF9wcm94eV9tZWFuKSkKCiMgRXh0cmFjdCB1bmlxdWUgbG9jYWxpdGllcwpsb2NhbGl0aWVzIDwtIHVuaXF1ZShkZl9maWx0ZXJlZCRMb2NhbGl0eSkKCiMgU2V0IFBERiBvdXRwdXQgcGF0aApvdXRwdXRfcGRmIDwtICIjL0NvbXBhcmF0aXZlX1Bsb3RzX0xwcm94eV9tZWFuX1BPTFlQT0xFU19BTExUT0dFVEhFUi5wZGYiCnBkZl9vcGVuZWQgPC0gRkFMU0UKCiMgSW5pdGlhbGl6ZSByZXN1bHRzIHRhYmxlCnN0YXRpc3RpY2FsX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBMb2NhbGl0eSA9IGNoYXJhY3RlcigpLAogIE1ldGhvZCA9IGNoYXJhY3RlcigpLAogIFByb2NlZGVuY2UgPSBjaGFyYWN0ZXIoKSwKICBLU19zdGF0aXN0aWMgPSBudW1lcmljKCksCiAgS1NfcF92YWx1ZSA9IG51bWVyaWMoKSwKICBXYXNzZXJzdGVpbiA9IG51bWVyaWMoKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKZm9yIChsb2MgaW4gbG9jYWxpdGllcykgewogIGNhdCgiXG5cbvCfk40gTG9jYWxpdHk6IiwgbG9jLCAiXG4iKQoKICBkZl9sb2MgPC0gZGZfZmlsdGVyZWQgJT4lIGZpbHRlcihMb2NhbGl0eSA9PSBsb2MpCiAgZnVsbF92YWxzIDwtIGRmX2xvYyAlPiUgZmlsdGVyKFRlc3NlbGwgPT0gImNvbXBsZXRlIikgJT4lIHB1bGwoTF9wcm94eV9tZWFuKQoKICBmb3IgKG1ldGhvZCBpbiB1bmlxdWUoZGZfbG9jJFRlc3NlbGwpKSB7CiAgICBpZiAobWV0aG9kID09ICJjb21wbGV0ZSIpIG5leHQKCiAgICBkZl9zdWJfYWxsIDwtIGRmX2xvYyAlPiUgZmlsdGVyKFRlc3NlbGwgPT0gbWV0aG9kICYgUHJvY2VkZW5jZSAlaW4lIGMoIkV4YW1pbmF0ZWQiLCAiUG9sZXMiKSkKICAgIGlmIChucm93KGRmX3N1Yl9hbGwpID09IDApIG5leHQKCiAgICAjIENvbXB1dGUgc3RhdGlzdGljcyBieSBwcm9jZWRlbmNlCiAgICBmb3IgKHByb2MgaW4gYygiRXhhbWluYXRlZCIsICJQb2xlcyIpKSB7CiAgICAgIGRmX3N1YiA8LSBkZl9sb2MgJT4lIGZpbHRlcihUZXNzZWxsID09IG1ldGhvZCwgUHJvY2VkZW5jZSA9PSBwcm9jKQogICAgICBpZiAobnJvdyhkZl9zdWIpID09IDApIG5leHQKCiAgICAgIHN1Yl92YWxzIDwtIGRmX3N1YiRMX3Byb3h5X21lYW4KICAgICAgbiA8LSBtaW4obGVuZ3RoKGZ1bGxfdmFscyksIGxlbmd0aChzdWJfdmFscykpCiAgICAgIGtzIDwtIGtzLnRlc3QoZnVsbF92YWxzLCBzdWJfdmFscykKICAgICAgd2FzcyA8LSBtZWFuKGFicyhzb3J0KGZ1bGxfdmFscylbMTpuXSAtIHNvcnQoc3ViX3ZhbHMpWzE6bl0pKQoKICAgICAgY2F0KCLwn5SOIE1ldGhvZDoiLCBtZXRob2QsICJ8IFByb2NlZGVuY2U6IiwgcHJvYywgIlxuIikKICAgICAgY2F0KCIgICBLUyBwLXZhbHVlOiIsIGtzJHAudmFsdWUsICJcbiIpCiAgICAgIGNhdCgiICAgS1Mgc3RhdGlzdGljOiIsIGtzJHN0YXRpc3RpYywgIlxuIikKICAgICAgY2F0KCIgICBBcHByb3guIFdhc3NlcnN0ZWluIGRpc3RhbmNlOiIsIHJvdW5kKHdhc3MsIDQpLCAiXG4iKQoKICAgICAgc3RhdGlzdGljYWxfcmVzdWx0cyA8LSByYmluZChzdGF0aXN0aWNhbF9yZXN1bHRzLCBkYXRhLmZyYW1lKAogICAgICAgIExvY2FsaXR5ID0gbG9jLAogICAgICAgIE1ldGhvZCA9IG1ldGhvZCwKICAgICAgICBQcm9jZWRlbmNlID0gcHJvYywKICAgICAgICBLU19zdGF0aXN0aWMgPSBhcy5udW1lcmljKGtzJHN0YXRpc3RpYyksCiAgICAgICAgS1NfcF92YWx1ZSA9IGFzLm51bWVyaWMoa3MkcC52YWx1ZSksCiAgICAgICAgV2Fzc2Vyc3RlaW4gPSByb3VuZCh3YXNzLCA0KSwKICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICAgICAgKSkKICAgIH0KCiAgICAjIEdlbmVyYXRlIGRlbnNpdHkgYW5kIFHigJNRIHBsb3RzCiAgICBpZiAoIXBkZl9vcGVuZWQpIHsKICAgICAgcGRmKG91dHB1dF9wZGYsIHdpZHRoID0gMTQsIGhlaWdodCA9IDYpCiAgICAgIHBkZl9vcGVuZWQgPC0gVFJVRQogICAgfQoKICAgICMgRGVuc2l0eSBwbG90CiAgICBwMSA8LSBnZ3Bsb3QoCiAgICAgIGRmX2xvYyAlPiUgZmlsdGVyKChUZXNzZWxsID09IG1ldGhvZCAmIFByb2NlZGVuY2UgJWluJSBjKCJFeGFtaW5hdGVkIiwgIlBvbGVzIikpIHwgVGVzc2VsbCA9PSAiY29tcGxldGUiKSwKICAgICAgYWVzKHggPSBMX3Byb3h5X21lYW4sIGZpbGwgPSBpbnRlcmFjdGlvbihUZXNzZWxsLCBQcm9jZWRlbmNlLCBkcm9wID0gVFJVRSkpCiAgICApICsKICAgICAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90IiwKICAgICAgICAgICB4ID0gIkxfcHJveHlfbWVhbiIsIHkgPSAiRGVuc2l0eSIsIGZpbGwgPSAiVGVzc2VsbGF0aW9uIC8gUHJvY2VkZW5jZSIpCgogICAgIyBR4oCTUSBwbG90CiAgICBxcV9kZnMgPC0gbGlzdCgpCiAgICBmb3IgKHByb2MgaW4gYygiRXhhbWluYXRlZCIsICJQb2xlcyIpKSB7CiAgICAgIGRmX3N1YiA8LSBkZl9sb2MgJT4lIGZpbHRlcihUZXNzZWxsID09IG1ldGhvZCwgUHJvY2VkZW5jZSA9PSBwcm9jKQogICAgICBpZiAobnJvdyhkZl9zdWIpID09IDApIG5leHQKCiAgICAgIHN1Yl92YWxzIDwtIGRmX3N1YiRMX3Byb3h5X21lYW4KICAgICAgbiA8LSBtaW4obGVuZ3RoKGZ1bGxfdmFscyksIGxlbmd0aChzdWJfdmFscykpCgogICAgICBxcV9kZnNbW3Byb2NdXSA8LSBkYXRhLmZyYW1lKAogICAgICAgIGNvbXBsZXRlID0gc29ydChmdWxsX3ZhbHMpWzE6bl0sCiAgICAgICAgc3ViID0gc29ydChzdWJfdmFscylbMTpuXSwKICAgICAgICBQcm9jZWRlbmNlID0gcHJvYwogICAgICApCiAgICB9CiAgICBxcV9kZl9hbGwgPC0gYmluZF9yb3dzKHFxX2RmcykKCiAgICBwMiA8LSBnZ3Bsb3QocXFfZGZfYWxsLCBhZXMoeCA9IGNvbXBsZXRlLCB5ID0gc3ViLCBjb2xvciA9IFByb2NlZGVuY2UpKSArCiAgICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICAgICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh0aXRsZSA9ICJR4oCTUSBQbG90IiwgeCA9ICJDb21wbGV0ZSBEaXN0cmlidXRpb24iLCB5ID0gbWV0aG9kKQoKICAgIGNvbWJpbmVkIDwtIGdnYXJyYW5nZShwMiwgcDEsIG5jb2wgPSAyLCB3aWR0aHMgPSBjKDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQgPSAicmlnaHQiKQoKICAgIGNvbWJpbmVkIDwtIGFubm90YXRlX2ZpZ3VyZShjb21iaW5lZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wID0gdGV4dF9ncm9iKHBhc3RlMChsb2MsICIgLyAiLCBtZXRob2QsICIgLyBDb21wYXJpc29uIHdpdGggRXhhbWluYXRlZCAmIFBvbGVzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpKQoKICAgIHByaW50KGNvbWJpbmVkKQogIH0KfQoKaWYgKHBkZl9vcGVuZWQpIHsKICBkZXYub2ZmKCkKICBjYXQoIlxu4pyFIFBERiBzdWNjZXNzZnVsbHkgZ2VuZXJhdGVkIHdpdGggYWxsIGNvbXBhcmlzb25zIGFuZCBzdGF0aXN0aWNzLlxuIikKfSBlbHNlIHsKICBjYXQoIlxu4pqg77iPIE5vIHBsb3RzIHdlcmUgZ2VuZXJhdGVkLiBQbGVhc2UgY2hlY2sgYXZhaWxhYmxlIGRhdGEuXG4iKQp9CgojIFNhdmUgc3RhdGlzdGljYWwgcmVzdWx0cyB0byBFeGNlbApvdXRwdXRfZXhjZWwgPC0gIiMvQ29tcGFyYXRpdmVfU3RhdHNfTHByb3h5X21lYW5fUE9MWVBPTEVTX0FMTFRPR0VUSEVSLnhsc3giCndyaXRlLnhsc3goc3RhdGlzdGljYWxfcmVzdWx0cywgb3V0cHV0X2V4Y2VsKQoKYGBgCg==