This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Ctrl+Shift+Enter.
library(readxl)
library(ggplot2)
library(dplyr)
library(tidyr)
# Part C
setwd("C:/Users/kalek/Downloads")
getwd()
# Read datasets
weekends <- read.csv("C:/Users/kalek/Downloads/lisbon_weekends.csv")
weekdays <- read.csv("C:/Users/kalek/Downloads/lisbon_weekdays.csv")
cols <- c(
"realSum", "cleanliness_rating", "guest_satisfaction_overall",
"dist", "metro_dist",
"attr_index", "rest_index"
)
# Summary statistics
summary_stats1 <- data.frame(
Mean = sapply(weekends[cols], mean, na.rm = TRUE),
SD = sapply(weekends[cols], sd, na.rm = TRUE),
Median = sapply(weekends[cols], median, na.rm = TRUE),
Min = sapply(weekends[cols], min, na.rm = TRUE),
Max = sapply(weekends[cols], max, na.rm = TRUE)
)
summary_stats2 <- data.frame(
Mean = sapply(weekdays[cols], mean, na.rm = TRUE),
SD = sapply(weekdays[cols], sd, na.rm = TRUE),
Median = sapply(weekdays[cols], median, na.rm = TRUE),
Min = sapply(weekdays[cols], min, na.rm = TRUE),
Max = sapply(weekdays[cols], max, na.rm = TRUE)
)
print("Summary Statistics for weekends:")
print(summary_stats1)
print("Summary Statistics for weekdays:")
print(summary_stats2)
columns_to_check <- c("room_type", "room_shared", "room_private", "person_capacity",
"host_is_superhost", "multi", "biz", "bedrooms")
boolean_cols <- c("room_shared", "room_private", "host_is_superhost", "multi", "biz")
non_boolean_cols <- c("room_type", "person_capacity", "bedrooms")
# Function to create frequency tables
create_freq_table_df <- function(data, columns) {
freq_tables <- list()
for (col in columns) {
freq_tbl <- as.data.frame(table(data[[col]], useNA = "ifany"))
colnames(freq_tbl) <- c(col, "Frequency") # Name the columns nicely
freq_tables[[col]] <- freq_tbl
}
return(freq_tables)
}
for (col in non_boolean_cols) {
unique_vals <- unique(weekends[[col]])
cat("\n--- Column:", col, "---\n")
cat("Number of unique values:", length(unique_vals), "\n")
cat("Unique values:", unique_vals, "\n")
}
# For non-boolean columns
non_bool_freq_weekends <- create_freq_table_df(weekends, non_boolean_cols)
bool_freq_weekends <- create_freq_table_df(weekends, boolean_cols)
non_bool_freq_weekdays <- create_freq_table_df(weekdays, non_boolean_cols)
bool_freq_weekdays <- create_freq_table_df(weekdays, boolean_cols)
weekends$person_capacity <- as.factor(weekends$person_capacity)
weekends$bedrooms <- as.factor(weekends$bedrooms)
weekdays$person_capacity <- as.factor(weekdays$person_capacity)
weekdays$bedrooms <- as.factor(weekdays$bedrooms)
cat_vars <- c("room_type", "room_shared", "room_private", "person_capacity",
"multi", "biz", "bedrooms")
target_var <- "host_is_superhost"
num_vars <- c("realSum", "cleanliness_rating", "guest_satisfaction_overall",
"dist", "metro_dist", "attr_index", "rest_index")
# 1. Chi-Square Tests: host_is_superhost vs categorical variables
cat("\n===== Chi-Square Tests (Categorical Variables) =====\n")
for (col in cat_vars) {
tbl <- table(weekends[[col]], weekends[[target_var]])
cat("\nChi-Square Test between", col, "and", target_var, "\n")
print(chisq.test(tbl))
}
# 2. T-Tests: host_is_superhost vs numerical variables
cat("\n===== T-Tests (Numerical Variables) =====\n")
for (col in num_vars) {
formula <- as.formula(paste(col, "~", target_var))
t_test_result <- t.test(formula, data = weekends)
cat("\nT-test for:", col, "\n")
print(t_test_result)
}
# 3. Correlation Matrix for numerical variables
num_data <- weekends %>% select(all_of(num_vars))
cor_matrix <- cor(num_data, use = "complete.obs")
# Plot correlation matrix
ggcorrplot(cor_matrix, lab = TRUE, title = "Correlation Matrix for Numerical Attributes")
install.packages("gt")
library(ggcorrplot)
library(broom) # for tidy test outputs
library(gt)
chi_square_results1 <- data.frame(Weekend_Variable = character(),
Chi_Square_Statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
t_test_results1 <- data.frame(Weekend_Variable = character(),
t_statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
for (col in cat_vars) {
tbl <- table(weekends[[col]], weekends[[target_var]])
chi_test <- chisq.test(tbl)
chi_square_results1 <- rbind(chi_square_results1,
data.frame(Variable = col,
Chi_Square_Statistic = chi_test$statistic,
p_value = chi_test$p.value))
}
# 2. T-Tests
for (col in num_vars) {
formula <- as.formula(paste(col, "~", target_var))
t_test <- t.test(formula, data = weekends)
t_test_results1 <- rbind(t_test_results1,
data.frame(Variable = col,
t_statistic = t_test$statistic,
p_value = t_test$p.value))
}
chi_square_results1 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
tab_header(title = "Chi-Square Test Results (Categorical Variables)") %>%
fmt_number(columns = c(Chi_Square_Statistic, p_value), decimals = 4)
t_test_results1 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
tab_header(title = "T-Test Results (Numerical Variables)") %>%
fmt_number(columns = c(t_statistic, p_value), decimals = 4)
num_data <- weekends %>% select(all_of(num_vars))
cor_matrix <- cor(num_data, use = "complete.obs")
ggcorrplot(cor_matrix, lab = TRUE, title = "Correlation Matrix for Numerical Attributes")
cat_vars1 <- c("room_type", "room_shared", "room_private", "person_capacity",
"multi", "biz", "bedrooms", "host_is_superhost")
num_vars1 <- c("cleanliness_rating", "guest_satisfaction_overall",
"dist", "metro_dist", "attr_index", "rest_index")
anova_results1 <- data.frame(Variable = character(),
F_statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
correlation_results1 <- data.frame(Variable = character(),
Correlation = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
# 1. ANOVA Tests: Categorical attributes vs realSum
for (col in cat_vars1) {
formula <- as.formula(paste("realSum ~", col))
anova_test <- aov(formula, data = weekends)
anova_summary <- summary(anova_test)
f_value <- anova_summary[[1]]$`F value`[1]
p_val <- anova_summary[[1]]$`Pr(>F)`[1]
anova_results1 <- rbind(anova_results1,
data.frame(Variable = col,
F_statistic = f_value,
p_value = p_val))
}
# 2. Correlation Tests: Numeric attributes vs realSum
for (col in num_vars1) {
cor_test <- cor.test(weekends[[col]], weekends$realSum, use = "complete.obs")
correlation_results1 <- rbind(correlation_results1,
data.frame(Variable = col,
Correlation = cor_test$estimate,
p_value = cor_test$p.value))
}
anova_results1 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
gt::fmt_number(columns = c(F_statistic, p_value), decimals = 4) %>%
tab_header(title = "ANOVA Test Results (Categorical Variables vs realSum)")
correlation_results1 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
gt::fmt_number(columns = c(Correlation, p_value), decimals = 4) %>%
tab_header(title = "Correlation Test Results (Numerical Variables vs realSum)")
num_data1 <- weekends %>% select(realSum, all_of(num_vars1))
cor_matrix1 <- cor(num_data1, use = "complete.obs")
ggcorrplot(cor_matrix1, lab = TRUE, title = "Correlation Matrix with realSum")
anova_results2 <- data.frame(Variable = character(),
F_statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
correlation_results2 <- data.frame(Variable = character(),
Correlation = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
for (col in cat_vars1) {
formula <- as.formula(paste("realSum ~", col))
anova_test <- aov(formula, data = weekdays)
anova_summary <- summary(anova_test)
f_value <- anova_summary[[1]]$`F value`[1]
p_val <- anova_summary[[1]]$`Pr(>F)`[1]
anova_results2 <- rbind(anova_results2,
data.frame(Variable = col,
F_statistic = f_value,
p_value = p_val))
}
# 2. Correlation Tests: Numeric attributes vs realSum
for (col in num_vars1) {
cor_test <- cor.test(weekdays[[col]], weekdays$realSum, use = "complete.obs")
correlation_results2 <- rbind(correlation_results2,
data.frame(Variable = col,
Correlation = cor_test$estimate,
p_value = cor_test$p.value))
}
anova_results2 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
gt::fmt_number(columns = c(F_statistic, p_value), decimals = 4) %>%
tab_header(title = "ANOVA Test Results_weekdays (Categorical Variables vs realSum)")
correlation_results2 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
gt::fmt_number(columns = c(Correlation, p_value), decimals = 4) %>%
tab_header(title = "Correlation Test Results_weekdays (Numerical Variables vs realSum)")
num_data1i <- weekdays %>% select(realSum, all_of(num_vars1))
cor_matrix1i <- cor(num_data1i, use = "complete.obs")
ggcorrplot(cor_matrix1i, lab = TRUE, title = "Correlation Matrix with realSum")
chi_square_results2 <- data.frame(Variable = character(),
Chi_Square_Statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
t_test_results2 <- data.frame(Variable = character(),
t_statistic = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE)
for (col in cat_vars) {
tbl <- table(weekdays[[col]], weekdays[[target_var]])
chi_test <- chisq.test(tbl)
chi_square_results2 <- rbind(chi_square_results2,
data.frame(Variable = col,
Chi_Square_Statistic = chi_test$statistic,
p_value = chi_test$p.value))
}
# 2. T-Tests
for (col in num_vars) {
formula <- as.formula(paste(col, "~", target_var))
t_test <- t.test(formula, data = weekdays)
t_test_results2 <- rbind(t_test_results2,
data.frame(Variable = col,
t_statistic = t_test$statistic,
p_value = t_test$p.value))
}
chi_square_results2 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
tab_header(title = "Chi-Square Test Results_weekdays (Categorical Variables)") %>%
fmt_number(columns = c(Chi_Square_Statistic, p_value), decimals = 4)
t_test_results2 %>%
mutate(Significant = ifelse(p_value < 0.05, "Yes", "No")) %>%
gt() %>%
tab_header(title = "T-Test Results_weekdays (Numerical Variables)") %>%
fmt_number(columns = c(t_statistic, p_value), decimals = 4)
num_datai <- weekends %>% select(all_of(num_vars))
cor_matrixi <- cor(num_datai, use = "complete.obs")
ggcorrplot(cor_matrix, lab = TRUE, title = "Correlation Matrix for Numerical Attributes")
cat_vars_f <- c("room_type", "room_shared", "room_private", "person_capacity", "multi", "biz", "bedrooms", "host_is_superhost")
weekends <- weekends %>%
mutate(across(all_of(cat_vars_f), as.factor))
weekdays <- weekdays %>%
mutate(across(all_of(cat_vars_f), as.factor))
# 1. Build Weekends Model
weekends_model <- lm(realSum ~ room_type + room_shared + room_private + person_capacity + multi + bedrooms +
host_is_superhost + cleanliness_rating + guest_satisfaction_overall +
dist + attr_index + rest_index,
data = weekends)
summary(weekends_model)
weekdays_model <- lm(realSum ~ room_type + room_shared + room_private + person_capacity + multi + biz + bedrooms +
host_is_superhost + cleanliness_rating + guest_satisfaction_overall +
dist + attr_index + rest_index,
data = weekdays)
summary(weekdays_model)
weekdays$room_private <- as.factor(weekdays$room_private)
weekends$room_private <- as.factor(weekends$room_private)
weekends$room_type <- relevel(as.factor(weekends$room_type), ref = "Entire home/apt")
# Rebuild the model
weekends_model_final <- lm(realSum ~ room_type + room_private + person_capacity +
bedrooms + guest_satisfaction_overall +
dist + attr_index + rest_index,
data = weekends)
summary(weekends_model_final)
plot(predict(weekends_model_final), weekends$realSum,
xlab = "Predicted Price", ylab = "Actual Price",
main = "Predicted vs Actual Prices - Weekends")
abline(0, 1, col = "red")
sqrt(mean((predict(weekends_model_final) - weekends$realSum)^2))
weekends_filtered <- weekends %>%
filter(!bedrooms %in% c(9, 10))
# Rebuild the model
weekends_model_better <- lm(realSum ~ room_type + person_capacity +
bedrooms + guest_satisfaction_overall +
dist + attr_index + rest_index,
data = weekends_filtered)
summary(weekends_model_better)
install.packages("modeest")
library(modeest)
columns_to_check <- c("room_type", "room_shared", "room_private", "person_capacity",
"host_is_superhost", "multi", "biz", "bedrooms")
all_columns <- colnames(weekends)
numerical_variable <- setdiff(all_columns, columns_to_check)
# 1. Plot frequency graphs for categorical variables
plot_freq_graphs <- function(data, dataset_name) {
for (var in columns_to_check) {
ggplot(data, aes_string(x = var)) +
geom_bar(fill = "skyblue") +
labs(title = paste("Frequency of", var, "in", dataset_name),
x = var, y = "Count") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) -> p
print(p)
}
}
# 2. Plot distribution graphs for numeric variables
plot_distribution_graphs <- function(data, dataset_name) {
for (var in numerical_variable) {
ggplot(data, aes_string(x = var)) +
geom_histogram(bins = 30, fill = "lightgreen", color = "black") +
labs(title = paste("Distribution of", var, "in", dataset_name),
x = var, y = "Frequency") +
theme_minimal() -> p
print(p)
}
}
# 3. Plot min, max, mean, median, mode for numeric variables
plot_statistics_graphs <- function(data, dataset_name) {
for (var in numerical_variable) {
var_data <- data[[var]]
var_data <- var_data[!is.na(var_data)] # Remove NAs
min_val <- min(var_data)
max_val <- max(var_data)
mean_val <- mean(var_data)
median_val <- median(var_data)
mode_val <- mfv(var_data) # Most frequent value (mode)
ggplot(data, aes_string(x = var)) +
geom_histogram(bins = 20, fill = "lightgrey", color = "black") +
geom_vline(xintercept = min_val, color = "blue", linetype = "dashed", size = 1, show.legend = TRUE) +
geom_vline(xintercept = max_val, color = "red", linetype = "dashed", size = 1, show.legend = TRUE) +
geom_vline(xintercept = mean_val, color = "green", linetype = "dashed", size = 1, show.legend = TRUE) +
geom_vline(xintercept = median_val, color = "purple", linetype = "dashed", size = 1, show.legend = TRUE) +
geom_vline(xintercept = mode_val, color = "orange", linetype = "dashed", size = 1, show.legend = TRUE) +
labs(title = paste("Min/Max/Mean/Median/Mode for", var, "in", dataset_name),
x = var, y = "Frequency") +
theme_minimal() -> p
print(p)
}
}
# Run for Weekends
cat("Plotting for Weekends Dataset...\n")
plot_freq_graphs(weekends, "Weekends")
plot_distribution_graphs(weekends, "Weekends")
plot_statistics_graphs(weekends, "Weekends")
# Run for Weekdays
cat("Plotting for Weekdays Dataset...\n")
plot_freq_graphs(weekdays, "Weekdays")
plot_distribution_graphs(weekdays, "Weekdays")
plot_statistics_graphs(weekdays, "Weekdays")
weekends_private <- weekends %>% filter(room_type == "Private room")
weekends_shared <- weekends %>% filter(room_type == "Shared room")
weekends_entire <- weekends %>% filter(room_type == "Entire home/apt")
weekdays_private <- weekdays %>% filter(room_type == "Private room")
weekdays_shared <- weekdays %>% filter(room_type == "Shared room")
weekdays_entire <- weekdays %>% filter(room_type == "Entire home/apt")
# 2. Plot histogram for Private Room
ggplot(weekends_private, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "skyblue", color = "black") +
labs(title = "Distribution of realSum - Private Room",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# 3. Plot histogram for Shared Room
ggplot(weekends_shared, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "lightcoral", color = "black") +
labs(title = "Distribution of realSum - Shared Room",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# 4. Plot histogram for Entire Home/Apt
ggplot(weekends_entire, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "lightgreen", color = "black") +
labs(title = "Distribution of realSum - Entire Home/Apt",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# 5. Plot histogram for Private Room_weekday
ggplot(weekdays_private, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "skyblue", color = "black") +
labs(title = "Distribution of realSum - Private Room_weekday",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# 6. Plot histogram for Shared Room_weekday
ggplot(weekdays_shared, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "lightcoral", color = "black") +
labs(title = "Distribution of realSum - Shared Room_weekday",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# 7. Plot histogram for Entire Home/Apt_weekday
ggplot(weekdays_entire, aes(x = realSum)) +
geom_histogram(bins = 20, fill = "lightgreen", color = "black") +
labs(title = "Distribution of realSum - Entire Home/Apt_weekday",
x = "Price (realSum)", y = "Count") +
theme_minimal()
# Violin plot
ggplot(weekends, aes(x = room_type, y = realSum)) +
geom_violin(fill = "lightgreen") +
geom_boxplot(width = 0.1, fill = "white") +
labs(title = "Price Distribution (realSum) by Room Type (Violin Plot)",
x = "Room Type", y = "Price (realSum)") +
theme_minimal()
# Violin plot
ggplot(weekdays, aes(x = room_type, y = realSum)) +
geom_violin(fill = "lightgreen") +
geom_boxplot(width = 0.1, fill = "white") +
labs(title = "Price Distribution (realSum) by Room Type (Violin Plot)_weekdays",
x = "Room Type", y = "Price (realSum)") +
theme_minimal()
ggplot(weekends, aes(x = room_type, y = realSum)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Price Distribution (realSum) by Room Type",
x = "Room Type", y = "Price (realSum)") +
theme_minimal()
ggplot(weekdays, aes(x = room_type, y = realSum)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Price Distribution (realSum) by Room Type_weekdays",
x = "Room Type", y = "Price (realSum)") +
theme_minimal()
predict_data <- data.frame(room_type = "Private room",
room_shared = "False",
room_private = "True",
person_capacity = "2",
multi = "1",
bedrooms = "1",
host_is_superhost = "True",
cleanliness_rating = 10,
guest_satisfaction_overall = 98,
dist = 4.3280410,
attr_index = 74.23002,
rest_index = 176.86793)
predict_realSum <- predict(weekends_model, newdata = predict_data)
cat("Predicted price for listing with given attribute values is: $", round(predict_realSum, 2))
predict_data1 <- data.frame(room_type = "Private room",
room_shared = "False",
room_private = "True",
person_capacity = "3",
multi = "1",
bedrooms = "2",
host_is_superhost = "False",
cleanliness_rating = 10,
guest_satisfaction_overall = 100,
dist = 5.3260420,
attr_index = 64.93882,
rest_index = 178.96643)
predict_realSum1 <- predict(weekends_model, newdata = predict_data1)
cat("Predicted price for listing with given attribute values is: $", round(predict_realSum1, 2))
Add a new chunk by clicking the Insert Chunk button on the
toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and
output will be saved alongside it (click the Preview button or
press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the
editor. Consequently, unlike Knit, Preview does not
run any R code chunks. Instead, the output of the chunk when it was last
run in the editor is displayed.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4KClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDdHJsK1NoaWZ0K0VudGVyKi4KCmBgYHtyfQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQoKIyBQYXJ0IEMKCnNldHdkKCJDOi9Vc2Vycy9rYWxlay9Eb3dubG9hZHMiKQpnZXR3ZCgpCmBgYAoKYGBge3J9CgojIFJlYWQgZGF0YXNldHMKd2Vla2VuZHMgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL2thbGVrL0Rvd25sb2Fkcy9saXNib25fd2Vla2VuZHMuY3N2IikKd2Vla2RheXMgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL2thbGVrL0Rvd25sb2Fkcy9saXNib25fd2Vla2RheXMuY3N2IikKCmBgYAoKYGBge3J9CmNvbHMgPC0gYygKICAicmVhbFN1bSIsICJjbGVhbmxpbmVzc19yYXRpbmciLCAiZ3Vlc3Rfc2F0aXNmYWN0aW9uX292ZXJhbGwiLAogICJkaXN0IiwgIm1ldHJvX2Rpc3QiLAogICJhdHRyX2luZGV4IiwgInJlc3RfaW5kZXgiCikKCiMgU3VtbWFyeSBzdGF0aXN0aWNzCnN1bW1hcnlfc3RhdHMxIDwtIGRhdGEuZnJhbWUoCiAgTWVhbiA9IHNhcHBseSh3ZWVrZW5kc1tjb2xzXSwgbWVhbiwgbmEucm0gPSBUUlVFKSwKICBTRCA9IHNhcHBseSh3ZWVrZW5kc1tjb2xzXSwgc2QsIG5hLnJtID0gVFJVRSksCiAgTWVkaWFuID0gc2FwcGx5KHdlZWtlbmRzW2NvbHNdLCBtZWRpYW4sIG5hLnJtID0gVFJVRSksCiAgTWluID0gc2FwcGx5KHdlZWtlbmRzW2NvbHNdLCBtaW4sIG5hLnJtID0gVFJVRSksCiAgTWF4ID0gc2FwcGx5KHdlZWtlbmRzW2NvbHNdLCBtYXgsIG5hLnJtID0gVFJVRSkKKQoKc3VtbWFyeV9zdGF0czIgPC0gZGF0YS5mcmFtZSgKICBNZWFuID0gc2FwcGx5KHdlZWtkYXlzW2NvbHNdLCBtZWFuLCBuYS5ybSA9IFRSVUUpLAogIFNEID0gc2FwcGx5KHdlZWtkYXlzW2NvbHNdLCBzZCwgbmEucm0gPSBUUlVFKSwKICBNZWRpYW4gPSBzYXBwbHkod2Vla2RheXNbY29sc10sIG1lZGlhbiwgbmEucm0gPSBUUlVFKSwKICBNaW4gPSBzYXBwbHkod2Vla2RheXNbY29sc10sIG1pbiwgbmEucm0gPSBUUlVFKSwKICBNYXggPSBzYXBwbHkod2Vla2RheXNbY29sc10sIG1heCwgbmEucm0gPSBUUlVFKQopCgpwcmludCgiU3VtbWFyeSBTdGF0aXN0aWNzIGZvciB3ZWVrZW5kczoiKQpwcmludChzdW1tYXJ5X3N0YXRzMSkKCnByaW50KCJTdW1tYXJ5IFN0YXRpc3RpY3MgZm9yIHdlZWtkYXlzOiIpCnByaW50KHN1bW1hcnlfc3RhdHMyKQoKYGBgCgpgYGB7cn0KY29sdW1uc190b19jaGVjayA8LSBjKCJyb29tX3R5cGUiLCAicm9vbV9zaGFyZWQiLCAicm9vbV9wcml2YXRlIiwgInBlcnNvbl9jYXBhY2l0eSIsIAogICAgICAgICAgICAgICAgICAgICAgImhvc3RfaXNfc3VwZXJob3N0IiwgIm11bHRpIiwgImJpeiIsICJiZWRyb29tcyIpCgpib29sZWFuX2NvbHMgPC0gYygicm9vbV9zaGFyZWQiLCAicm9vbV9wcml2YXRlIiwgImhvc3RfaXNfc3VwZXJob3N0IiwgIm11bHRpIiwgImJpeiIpCm5vbl9ib29sZWFuX2NvbHMgPC0gYygicm9vbV90eXBlIiwgInBlcnNvbl9jYXBhY2l0eSIsICJiZWRyb29tcyIpCgojIEZ1bmN0aW9uIHRvIGNyZWF0ZSBmcmVxdWVuY3kgdGFibGVzCmNyZWF0ZV9mcmVxX3RhYmxlX2RmIDwtIGZ1bmN0aW9uKGRhdGEsIGNvbHVtbnMpIHsKICBmcmVxX3RhYmxlcyA8LSBsaXN0KCkKICAKICBmb3IgKGNvbCBpbiBjb2x1bW5zKSB7CiAgICBmcmVxX3RibCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdGFbW2NvbF1dLCB1c2VOQSA9ICJpZmFueSIpKQogICAgY29sbmFtZXMoZnJlcV90YmwpIDwtIGMoY29sLCAiRnJlcXVlbmN5IikgICMgTmFtZSB0aGUgY29sdW1ucyBuaWNlbHkKICAgIGZyZXFfdGFibGVzW1tjb2xdXSA8LSBmcmVxX3RibAogIH0KICByZXR1cm4oZnJlcV90YWJsZXMpCn0KCmZvciAoY29sIGluIG5vbl9ib29sZWFuX2NvbHMpIHsKICB1bmlxdWVfdmFscyA8LSB1bmlxdWUod2Vla2VuZHNbW2NvbF1dKQogIGNhdCgiXG4tLS0gQ29sdW1uOiIsIGNvbCwgIi0tLVxuIikKICBjYXQoIk51bWJlciBvZiB1bmlxdWUgdmFsdWVzOiIsIGxlbmd0aCh1bmlxdWVfdmFscyksICJcbiIpCiAgY2F0KCJVbmlxdWUgdmFsdWVzOiIsIHVuaXF1ZV92YWxzLCAiXG4iKQp9CgojIEZvciBub24tYm9vbGVhbiBjb2x1bW5zCm5vbl9ib29sX2ZyZXFfd2Vla2VuZHMgPC0gY3JlYXRlX2ZyZXFfdGFibGVfZGYod2Vla2VuZHMsIG5vbl9ib29sZWFuX2NvbHMpCmJvb2xfZnJlcV93ZWVrZW5kcyA8LSBjcmVhdGVfZnJlcV90YWJsZV9kZih3ZWVrZW5kcywgYm9vbGVhbl9jb2xzKQoKYGBgCgpgYGB7cn0Kbm9uX2Jvb2xfZnJlcV93ZWVrZGF5cyA8LSBjcmVhdGVfZnJlcV90YWJsZV9kZih3ZWVrZGF5cywgbm9uX2Jvb2xlYW5fY29scykKYm9vbF9mcmVxX3dlZWtkYXlzIDwtIGNyZWF0ZV9mcmVxX3RhYmxlX2RmKHdlZWtkYXlzLCBib29sZWFuX2NvbHMpCmBgYAoKYGBge3J9CndlZWtlbmRzJHBlcnNvbl9jYXBhY2l0eSA8LSBhcy5mYWN0b3Iod2Vla2VuZHMkcGVyc29uX2NhcGFjaXR5KQp3ZWVrZW5kcyRiZWRyb29tcyA8LSBhcy5mYWN0b3Iod2Vla2VuZHMkYmVkcm9vbXMpCndlZWtkYXlzJHBlcnNvbl9jYXBhY2l0eSA8LSBhcy5mYWN0b3Iod2Vla2RheXMkcGVyc29uX2NhcGFjaXR5KQp3ZWVrZGF5cyRiZWRyb29tcyA8LSBhcy5mYWN0b3Iod2Vla2RheXMkYmVkcm9vbXMpCgpjYXRfdmFycyA8LSBjKCJyb29tX3R5cGUiLCAicm9vbV9zaGFyZWQiLCAicm9vbV9wcml2YXRlIiwgInBlcnNvbl9jYXBhY2l0eSIsIAogICAgICAgICAgICAgICJtdWx0aSIsICJiaXoiLCAiYmVkcm9vbXMiKQp0YXJnZXRfdmFyIDwtICJob3N0X2lzX3N1cGVyaG9zdCIKbnVtX3ZhcnMgPC0gYygicmVhbFN1bSIsICJjbGVhbmxpbmVzc19yYXRpbmciLCAiZ3Vlc3Rfc2F0aXNmYWN0aW9uX292ZXJhbGwiLAogICAgICAgICAgICAgICJkaXN0IiwgIm1ldHJvX2Rpc3QiLCAiYXR0cl9pbmRleCIsICJyZXN0X2luZGV4IikKCiMgMS4gQ2hpLVNxdWFyZSBUZXN0czogaG9zdF9pc19zdXBlcmhvc3QgdnMgY2F0ZWdvcmljYWwgdmFyaWFibGVzCmNhdCgiXG49PT09PSBDaGktU3F1YXJlIFRlc3RzIChDYXRlZ29yaWNhbCBWYXJpYWJsZXMpID09PT09XG4iKQpmb3IgKGNvbCBpbiBjYXRfdmFycykgewogIHRibCA8LSB0YWJsZSh3ZWVrZW5kc1tbY29sXV0sIHdlZWtlbmRzW1t0YXJnZXRfdmFyXV0pCiAgY2F0KCJcbkNoaS1TcXVhcmUgVGVzdCBiZXR3ZWVuIiwgY29sLCAiYW5kIiwgdGFyZ2V0X3ZhciwgIlxuIikKICBwcmludChjaGlzcS50ZXN0KHRibCkpCn0KCiMgMi4gVC1UZXN0czogaG9zdF9pc19zdXBlcmhvc3QgdnMgbnVtZXJpY2FsIHZhcmlhYmxlcwpjYXQoIlxuPT09PT0gVC1UZXN0cyAoTnVtZXJpY2FsIFZhcmlhYmxlcykgPT09PT1cbiIpCmZvciAoY29sIGluIG51bV92YXJzKSB7CiAgZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKGNvbCwgIn4iLCB0YXJnZXRfdmFyKSkKICB0X3Rlc3RfcmVzdWx0IDwtIHQudGVzdChmb3JtdWxhLCBkYXRhID0gd2Vla2VuZHMpCiAgY2F0KCJcblQtdGVzdCBmb3I6IiwgY29sLCAiXG4iKQogIHByaW50KHRfdGVzdF9yZXN1bHQpCn0KCiMgMy4gQ29ycmVsYXRpb24gTWF0cml4IGZvciBudW1lcmljYWwgdmFyaWFibGVzCm51bV9kYXRhIDwtIHdlZWtlbmRzICU+JSBzZWxlY3QoYWxsX29mKG51bV92YXJzKSkKCmNvcl9tYXRyaXggPC0gY29yKG51bV9kYXRhLCB1c2UgPSAiY29tcGxldGUub2JzIikKCiMgUGxvdCBjb3JyZWxhdGlvbiBtYXRyaXgKZ2djb3JycGxvdChjb3JfbWF0cml4LCBsYWIgPSBUUlVFLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXggZm9yIE51bWVyaWNhbCBBdHRyaWJ1dGVzIikKYGBgCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZ3QiKQpsaWJyYXJ5KGdnY29ycnBsb3QpCmxpYnJhcnkoYnJvb20pICAgICAjIGZvciB0aWR5IHRlc3Qgb3V0cHV0cwpsaWJyYXJ5KGd0KSAKCmNoaV9zcXVhcmVfcmVzdWx0czEgPC0gZGF0YS5mcmFtZShXZWVrZW5kX1ZhcmlhYmxlID0gY2hhcmFjdGVyKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDaGlfU3F1YXJlX1N0YXRpc3RpYyA9IG51bWVyaWMoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgp0X3Rlc3RfcmVzdWx0czEgPC0gZGF0YS5mcmFtZShXZWVrZW5kX1ZhcmlhYmxlID0gY2hhcmFjdGVyKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRfc3RhdGlzdGljID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgpmb3IgKGNvbCBpbiBjYXRfdmFycykgewogIHRibCA8LSB0YWJsZSh3ZWVrZW5kc1tbY29sXV0sIHdlZWtlbmRzW1t0YXJnZXRfdmFyXV0pCiAgY2hpX3Rlc3QgPC0gY2hpc3EudGVzdCh0YmwpCiAgCiAgY2hpX3NxdWFyZV9yZXN1bHRzMSA8LSByYmluZChjaGlfc3F1YXJlX3Jlc3VsdHMxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDaGlfU3F1YXJlX1N0YXRpc3RpYyA9IGNoaV90ZXN0JHN0YXRpc3RpYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gY2hpX3Rlc3QkcC52YWx1ZSkpCn0KCiMgMi4gVC1UZXN0cwpmb3IgKGNvbCBpbiBudW1fdmFycykgewogIGZvcm11bGEgPC0gYXMuZm9ybXVsYShwYXN0ZShjb2wsICJ+IiwgdGFyZ2V0X3ZhcikpCiAgdF90ZXN0IDwtIHQudGVzdChmb3JtdWxhLCBkYXRhID0gd2Vla2VuZHMpCiAgCiAgdF90ZXN0X3Jlc3VsdHMxIDwtIHJiaW5kKHRfdGVzdF9yZXN1bHRzMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRfc3RhdGlzdGljID0gdF90ZXN0JHN0YXRpc3RpYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSB0X3Rlc3QkcC52YWx1ZSkpCn0KCgpjaGlfc3F1YXJlX3Jlc3VsdHMxICU+JQogIG11dGF0ZShTaWduaWZpY2FudCA9IGlmZWxzZShwX3ZhbHVlIDwgMC4wNSwgIlllcyIsICJObyIpKSAlPiUKICBndCgpICU+JQogIHRhYl9oZWFkZXIodGl0bGUgPSAiQ2hpLVNxdWFyZSBUZXN0IFJlc3VsdHMgKENhdGVnb3JpY2FsIFZhcmlhYmxlcykiKSAlPiUKICBmbXRfbnVtYmVyKGNvbHVtbnMgPSBjKENoaV9TcXVhcmVfU3RhdGlzdGljLCBwX3ZhbHVlKSwgZGVjaW1hbHMgPSA0KQoKdF90ZXN0X3Jlc3VsdHMxICU+JQogIG11dGF0ZShTaWduaWZpY2FudCA9IGlmZWxzZShwX3ZhbHVlIDwgMC4wNSwgIlllcyIsICJObyIpKSAlPiUKICBndCgpICU+JQogIHRhYl9oZWFkZXIodGl0bGUgPSAiVC1UZXN0IFJlc3VsdHMgKE51bWVyaWNhbCBWYXJpYWJsZXMpIikgJT4lCiAgZm10X251bWJlcihjb2x1bW5zID0gYyh0X3N0YXRpc3RpYywgcF92YWx1ZSksIGRlY2ltYWxzID0gNCkKCm51bV9kYXRhIDwtIHdlZWtlbmRzICU+JSBzZWxlY3QoYWxsX29mKG51bV92YXJzKSkKY29yX21hdHJpeCA8LSBjb3IobnVtX2RhdGEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKZ2djb3JycGxvdChjb3JfbWF0cml4LCBsYWIgPSBUUlVFLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXggZm9yIE51bWVyaWNhbCBBdHRyaWJ1dGVzIikKYGBgCgpgYGB7cn0KY2F0X3ZhcnMxIDwtIGMoInJvb21fdHlwZSIsICJyb29tX3NoYXJlZCIsICJyb29tX3ByaXZhdGUiLCAicGVyc29uX2NhcGFjaXR5IiwgCiAgICAgICAgICAgICAgIm11bHRpIiwgImJpeiIsICJiZWRyb29tcyIsICJob3N0X2lzX3N1cGVyaG9zdCIpCm51bV92YXJzMSA8LSBjKCJjbGVhbmxpbmVzc19yYXRpbmciLCAiZ3Vlc3Rfc2F0aXNmYWN0aW9uX292ZXJhbGwiLAogICAgICAgICAgICAgICJkaXN0IiwgIm1ldHJvX2Rpc3QiLCAiYXR0cl9pbmRleCIsICJyZXN0X2luZGV4IikKCmFub3ZhX3Jlc3VsdHMxIDwtIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBjaGFyYWN0ZXIoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBGX3N0YXRpc3RpYyA9IG51bWVyaWMoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmNvcnJlbGF0aW9uX3Jlc3VsdHMxIDwtIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBjaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvcnJlbGF0aW9uID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF92YWx1ZSA9IG51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiMgMS4gQU5PVkEgVGVzdHM6IENhdGVnb3JpY2FsIGF0dHJpYnV0ZXMgdnMgcmVhbFN1bQpmb3IgKGNvbCBpbiBjYXRfdmFyczEpIHsKICBmb3JtdWxhIDwtIGFzLmZvcm11bGEocGFzdGUoInJlYWxTdW0gfiIsIGNvbCkpCiAgYW5vdmFfdGVzdCA8LSBhb3YoZm9ybXVsYSwgZGF0YSA9IHdlZWtlbmRzKQogIGFub3ZhX3N1bW1hcnkgPC0gc3VtbWFyeShhbm92YV90ZXN0KQogIAogIGZfdmFsdWUgPC0gYW5vdmFfc3VtbWFyeVtbMV1dJGBGIHZhbHVlYFsxXQogIHBfdmFsIDwtIGFub3ZhX3N1bW1hcnlbWzFdXSRgUHIoPkYpYFsxXQogIAogIGFub3ZhX3Jlc3VsdHMxIDwtIHJiaW5kKGFub3ZhX3Jlc3VsdHMxLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRl9zdGF0aXN0aWMgPSBmX3ZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gcF92YWwpKQp9CgojIDIuIENvcnJlbGF0aW9uIFRlc3RzOiBOdW1lcmljIGF0dHJpYnV0ZXMgdnMgcmVhbFN1bQpmb3IgKGNvbCBpbiBudW1fdmFyczEpIHsKICBjb3JfdGVzdCA8LSBjb3IudGVzdCh3ZWVrZW5kc1tbY29sXV0sIHdlZWtlbmRzJHJlYWxTdW0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQogIAogIGNvcnJlbGF0aW9uX3Jlc3VsdHMxIDwtIHJiaW5kKGNvcnJlbGF0aW9uX3Jlc3VsdHMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29ycmVsYXRpb24gPSBjb3JfdGVzdCRlc3RpbWF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF92YWx1ZSA9IGNvcl90ZXN0JHAudmFsdWUpKQp9CgoKYW5vdmFfcmVzdWx0czEgJT4lCiAgbXV0YXRlKFNpZ25pZmljYW50ID0gaWZlbHNlKHBfdmFsdWUgPCAwLjA1LCAiWWVzIiwgIk5vIikpICU+JQogIGd0KCkgJT4lCiAgZ3Q6OmZtdF9udW1iZXIoY29sdW1ucyA9IGMoRl9zdGF0aXN0aWMsIHBfdmFsdWUpLCBkZWNpbWFscyA9IDQpICU+JQogIHRhYl9oZWFkZXIodGl0bGUgPSAiQU5PVkEgVGVzdCBSZXN1bHRzIChDYXRlZ29yaWNhbCBWYXJpYWJsZXMgdnMgcmVhbFN1bSkiKQoKY29ycmVsYXRpb25fcmVzdWx0czEgJT4lCiAgbXV0YXRlKFNpZ25pZmljYW50ID0gaWZlbHNlKHBfdmFsdWUgPCAwLjA1LCAiWWVzIiwgIk5vIikpICU+JQogIGd0KCkgJT4lCiAgZ3Q6OmZtdF9udW1iZXIoY29sdW1ucyA9IGMoQ29ycmVsYXRpb24sIHBfdmFsdWUpLCBkZWNpbWFscyA9IDQpICU+JQogIHRhYl9oZWFkZXIodGl0bGUgPSAiQ29ycmVsYXRpb24gVGVzdCBSZXN1bHRzIChOdW1lcmljYWwgVmFyaWFibGVzIHZzIHJlYWxTdW0pIikKIApudW1fZGF0YTEgPC0gd2Vla2VuZHMgJT4lIHNlbGVjdChyZWFsU3VtLCBhbGxfb2YobnVtX3ZhcnMxKSkKY29yX21hdHJpeDEgPC0gY29yKG51bV9kYXRhMSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpnZ2NvcnJwbG90KGNvcl9tYXRyaXgxLCBsYWIgPSBUUlVFLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXggd2l0aCByZWFsU3VtIikKYGBgCgpgYGB7cn0KYW5vdmFfcmVzdWx0czIgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNoYXJhY3RlcigpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZfc3RhdGlzdGljID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKY29ycmVsYXRpb25fcmVzdWx0czIgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29ycmVsYXRpb24gPSBudW1lcmljKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKZm9yIChjb2wgaW4gY2F0X3ZhcnMxKSB7CiAgZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJyZWFsU3VtIH4iLCBjb2wpKQogIGFub3ZhX3Rlc3QgPC0gYW92KGZvcm11bGEsIGRhdGEgPSB3ZWVrZGF5cykKICBhbm92YV9zdW1tYXJ5IDwtIHN1bW1hcnkoYW5vdmFfdGVzdCkKICAKICBmX3ZhbHVlIDwtIGFub3ZhX3N1bW1hcnlbWzFdXSRgRiB2YWx1ZWBbMV0KICBwX3ZhbCA8LSBhbm92YV9zdW1tYXJ5W1sxXV0kYFByKD5GKWBbMV0KICAKICBhbm92YV9yZXN1bHRzMiA8LSByYmluZChhbm92YV9yZXN1bHRzMiwKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBjb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZfc3RhdGlzdGljID0gZl92YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF92YWx1ZSA9IHBfdmFsKSkKfQoKIyAyLiBDb3JyZWxhdGlvbiBUZXN0czogTnVtZXJpYyBhdHRyaWJ1dGVzIHZzIHJlYWxTdW0KZm9yIChjb2wgaW4gbnVtX3ZhcnMxKSB7CiAgY29yX3Rlc3QgPC0gY29yLnRlc3Qod2Vla2RheXNbW2NvbF1dLCB3ZWVrZGF5cyRyZWFsU3VtLCB1c2UgPSAiY29tcGxldGUub2JzIikKICAKICBjb3JyZWxhdGlvbl9yZXN1bHRzMiA8LSByYmluZChjb3JyZWxhdGlvbl9yZXN1bHRzMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBjb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvcnJlbGF0aW9uID0gY29yX3Rlc3QkZXN0aW1hdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSBjb3JfdGVzdCRwLnZhbHVlKSkKfQoKCmFub3ZhX3Jlc3VsdHMyICU+JQogIG11dGF0ZShTaWduaWZpY2FudCA9IGlmZWxzZShwX3ZhbHVlIDwgMC4wNSwgIlllcyIsICJObyIpKSAlPiUKICBndCgpICU+JQogIGd0OjpmbXRfbnVtYmVyKGNvbHVtbnMgPSBjKEZfc3RhdGlzdGljLCBwX3ZhbHVlKSwgZGVjaW1hbHMgPSA0KSAlPiUKICB0YWJfaGVhZGVyKHRpdGxlID0gIkFOT1ZBIFRlc3QgUmVzdWx0c193ZWVrZGF5cyAoQ2F0ZWdvcmljYWwgVmFyaWFibGVzIHZzIHJlYWxTdW0pIikKCmNvcnJlbGF0aW9uX3Jlc3VsdHMyICU+JQogIG11dGF0ZShTaWduaWZpY2FudCA9IGlmZWxzZShwX3ZhbHVlIDwgMC4wNSwgIlllcyIsICJObyIpKSAlPiUKICBndCgpICU+JQogIGd0OjpmbXRfbnVtYmVyKGNvbHVtbnMgPSBjKENvcnJlbGF0aW9uLCBwX3ZhbHVlKSwgZGVjaW1hbHMgPSA0KSAlPiUKICB0YWJfaGVhZGVyKHRpdGxlID0gIkNvcnJlbGF0aW9uIFRlc3QgUmVzdWx0c193ZWVrZGF5cyAoTnVtZXJpY2FsIFZhcmlhYmxlcyB2cyByZWFsU3VtKSIpCgpudW1fZGF0YTFpIDwtIHdlZWtkYXlzICU+JSBzZWxlY3QocmVhbFN1bSwgYWxsX29mKG51bV92YXJzMSkpCmNvcl9tYXRyaXgxaSA8LSBjb3IobnVtX2RhdGExaSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpnZ2NvcnJwbG90KGNvcl9tYXRyaXgxaSwgbGFiID0gVFJVRSwgdGl0bGUgPSAiQ29ycmVsYXRpb24gTWF0cml4IHdpdGggcmVhbFN1bSIpCmBgYAoKYGBge3J9CmNoaV9zcXVhcmVfcmVzdWx0czIgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSA9IGNoYXJhY3RlcigpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2hpX1NxdWFyZV9TdGF0aXN0aWMgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwX3ZhbHVlID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKdF90ZXN0X3Jlc3VsdHMyIDwtIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBjaGFyYWN0ZXIoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdF9zdGF0aXN0aWMgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmZvciAoY29sIGluIGNhdF92YXJzKSB7CiAgdGJsIDwtIHRhYmxlKHdlZWtkYXlzW1tjb2xdXSwgd2Vla2RheXNbW3RhcmdldF92YXJdXSkKICBjaGlfdGVzdCA8LSBjaGlzcS50ZXN0KHRibCkKICAKICBjaGlfc3F1YXJlX3Jlc3VsdHMyIDwtIHJiaW5kKGNoaV9zcXVhcmVfcmVzdWx0czIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKFZhcmlhYmxlID0gY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENoaV9TcXVhcmVfU3RhdGlzdGljID0gY2hpX3Rlc3Qkc3RhdGlzdGljLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBfdmFsdWUgPSBjaGlfdGVzdCRwLnZhbHVlKSkKfQoKIyAyLiBULVRlc3RzCmZvciAoY29sIGluIG51bV92YXJzKSB7CiAgZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKGNvbCwgIn4iLCB0YXJnZXRfdmFyKSkKICB0X3Rlc3QgPC0gdC50ZXN0KGZvcm11bGEsIGRhdGEgPSB3ZWVrZGF5cykKICAKICB0X3Rlc3RfcmVzdWx0czIgPC0gcmJpbmQodF90ZXN0X3Jlc3VsdHMyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKFZhcmlhYmxlID0gY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdF9zdGF0aXN0aWMgPSB0X3Rlc3Qkc3RhdGlzdGljLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcF92YWx1ZSA9IHRfdGVzdCRwLnZhbHVlKSkKfQoKCmNoaV9zcXVhcmVfcmVzdWx0czIgJT4lCiAgbXV0YXRlKFNpZ25pZmljYW50ID0gaWZlbHNlKHBfdmFsdWUgPCAwLjA1LCAiWWVzIiwgIk5vIikpICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcih0aXRsZSA9ICJDaGktU3F1YXJlIFRlc3QgUmVzdWx0c193ZWVrZGF5cyAoQ2F0ZWdvcmljYWwgVmFyaWFibGVzKSIpICU+JQogIGZtdF9udW1iZXIoY29sdW1ucyA9IGMoQ2hpX1NxdWFyZV9TdGF0aXN0aWMsIHBfdmFsdWUpLCBkZWNpbWFscyA9IDQpCgp0X3Rlc3RfcmVzdWx0czIgJT4lCiAgbXV0YXRlKFNpZ25pZmljYW50ID0gaWZlbHNlKHBfdmFsdWUgPCAwLjA1LCAiWWVzIiwgIk5vIikpICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcih0aXRsZSA9ICJULVRlc3QgUmVzdWx0c193ZWVrZGF5cyAoTnVtZXJpY2FsIFZhcmlhYmxlcykiKSAlPiUKICBmbXRfbnVtYmVyKGNvbHVtbnMgPSBjKHRfc3RhdGlzdGljLCBwX3ZhbHVlKSwgZGVjaW1hbHMgPSA0KQoKCm51bV9kYXRhaSA8LSB3ZWVrZW5kcyAlPiUgc2VsZWN0KGFsbF9vZihudW1fdmFycykpCmNvcl9tYXRyaXhpIDwtIGNvcihudW1fZGF0YWksIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKZ2djb3JycGxvdChjb3JfbWF0cml4LCBsYWIgPSBUUlVFLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXggZm9yIE51bWVyaWNhbCBBdHRyaWJ1dGVzIikKYGBgCgpgYGB7cn0KY2F0X3ZhcnNfZiA8LSBjKCJyb29tX3R5cGUiLCAicm9vbV9zaGFyZWQiLCAicm9vbV9wcml2YXRlIiwgInBlcnNvbl9jYXBhY2l0eSIsICJtdWx0aSIsICJiaXoiLCAiYmVkcm9vbXMiLCAiaG9zdF9pc19zdXBlcmhvc3QiKQp3ZWVrZW5kcyA8LSB3ZWVrZW5kcyAlPiUKICBtdXRhdGUoYWNyb3NzKGFsbF9vZihjYXRfdmFyc19mKSwgYXMuZmFjdG9yKSkKCndlZWtkYXlzIDwtIHdlZWtkYXlzICU+JQogIG11dGF0ZShhY3Jvc3MoYWxsX29mKGNhdF92YXJzX2YpLCBhcy5mYWN0b3IpKQoKIyAxLiBCdWlsZCBXZWVrZW5kcyBNb2RlbAp3ZWVrZW5kc19tb2RlbCA8LSBsbShyZWFsU3VtIH4gcm9vbV90eXBlICsgcm9vbV9zaGFyZWQgKyByb29tX3ByaXZhdGUgKyBwZXJzb25fY2FwYWNpdHkgKyBtdWx0aSArIGJlZHJvb21zICsKICAgICAgICAgICAgICAgICAgICAgaG9zdF9pc19zdXBlcmhvc3QgKyBjbGVhbmxpbmVzc19yYXRpbmcgKyBndWVzdF9zYXRpc2ZhY3Rpb25fb3ZlcmFsbCArCiAgICAgICAgICAgICAgICAgICAgIGRpc3QgKyBhdHRyX2luZGV4ICsgcmVzdF9pbmRleCwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHdlZWtlbmRzKQoKc3VtbWFyeSh3ZWVrZW5kc19tb2RlbCkKYGBgCgpgYGB7cn0Kd2Vla2RheXNfbW9kZWwgPC0gbG0ocmVhbFN1bSB+IHJvb21fdHlwZSArIHJvb21fc2hhcmVkICsgcm9vbV9wcml2YXRlICsgcGVyc29uX2NhcGFjaXR5ICsgbXVsdGkgKyBiaXogKyBiZWRyb29tcyArCiAgICAgICAgICAgICAgICAgICAgIGhvc3RfaXNfc3VwZXJob3N0ICsgY2xlYW5saW5lc3NfcmF0aW5nICsgZ3Vlc3Rfc2F0aXNmYWN0aW9uX292ZXJhbGwgKwogICAgICAgICAgICAgICAgICAgICBkaXN0ICsgYXR0cl9pbmRleCArIHJlc3RfaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB3ZWVrZGF5cykKCnN1bW1hcnkod2Vla2RheXNfbW9kZWwpCmBgYAoKYGBge3J9CndlZWtkYXlzJHJvb21fcHJpdmF0ZSA8LSBhcy5mYWN0b3Iod2Vla2RheXMkcm9vbV9wcml2YXRlKQp3ZWVrZW5kcyRyb29tX3ByaXZhdGUgPC0gYXMuZmFjdG9yKHdlZWtlbmRzJHJvb21fcHJpdmF0ZSkKCndlZWtlbmRzJHJvb21fdHlwZSA8LSByZWxldmVsKGFzLmZhY3Rvcih3ZWVrZW5kcyRyb29tX3R5cGUpLCByZWYgPSAiRW50aXJlIGhvbWUvYXB0IikKCiMgUmVidWlsZCB0aGUgbW9kZWwKd2Vla2VuZHNfbW9kZWxfZmluYWwgPC0gbG0ocmVhbFN1bSB+IHJvb21fdHlwZSArIHJvb21fcHJpdmF0ZSArIHBlcnNvbl9jYXBhY2l0eSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlZHJvb21zICsgZ3Vlc3Rfc2F0aXNmYWN0aW9uX292ZXJhbGwgKwogICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0ICsgYXR0cl9pbmRleCArIHJlc3RfaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB3ZWVrZW5kcykKCnN1bW1hcnkod2Vla2VuZHNfbW9kZWxfZmluYWwpCmBgYAoKYGBge3J9CnBsb3QocHJlZGljdCh3ZWVrZW5kc19tb2RlbF9maW5hbCksIHdlZWtlbmRzJHJlYWxTdW0sCiAgICAgeGxhYiA9ICJQcmVkaWN0ZWQgUHJpY2UiLCB5bGFiID0gIkFjdHVhbCBQcmljZSIsCiAgICAgbWFpbiA9ICJQcmVkaWN0ZWQgdnMgQWN0dWFsIFByaWNlcyAtIFdlZWtlbmRzIikKYWJsaW5lKDAsIDEsIGNvbCA9ICJyZWQiKQpgYGAKCmBgYHtyfQpzcXJ0KG1lYW4oKHByZWRpY3Qod2Vla2VuZHNfbW9kZWxfZmluYWwpIC0gd2Vla2VuZHMkcmVhbFN1bSleMikpCmBgYAoKYGBge3J9CndlZWtlbmRzX2ZpbHRlcmVkIDwtIHdlZWtlbmRzICU+JQogIGZpbHRlcighYmVkcm9vbXMgJWluJSBjKDksIDEwKSkKCiMgUmVidWlsZCB0aGUgbW9kZWwKd2Vla2VuZHNfbW9kZWxfYmV0dGVyIDwtIGxtKHJlYWxTdW0gfiByb29tX3R5cGUgKyBwZXJzb25fY2FwYWNpdHkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVkcm9vbXMgKyBndWVzdF9zYXRpc2ZhY3Rpb25fb3ZlcmFsbCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0ICsgYXR0cl9pbmRleCArIHJlc3RfaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gd2Vla2VuZHNfZmlsdGVyZWQpCgpzdW1tYXJ5KHdlZWtlbmRzX21vZGVsX2JldHRlcikKCmBgYAoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoIm1vZGVlc3QiKQpsaWJyYXJ5KG1vZGVlc3QpCgpjb2x1bW5zX3RvX2NoZWNrIDwtIGMoInJvb21fdHlwZSIsICJyb29tX3NoYXJlZCIsICJyb29tX3ByaXZhdGUiLCAicGVyc29uX2NhcGFjaXR5IiwgCiAgICAgICAgICAgICAgICAgICAgICAiaG9zdF9pc19zdXBlcmhvc3QiLCAibXVsdGkiLCAiYml6IiwgImJlZHJvb21zIikKCmFsbF9jb2x1bW5zIDwtIGNvbG5hbWVzKHdlZWtlbmRzKQpudW1lcmljYWxfdmFyaWFibGUgPC0gc2V0ZGlmZihhbGxfY29sdW1ucywgY29sdW1uc190b19jaGVjaykKCiMgMS4gUGxvdCBmcmVxdWVuY3kgZ3JhcGhzIGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKcGxvdF9mcmVxX2dyYXBocyA8LSBmdW5jdGlvbihkYXRhLCBkYXRhc2V0X25hbWUpIHsKICBmb3IgKHZhciBpbiBjb2x1bW5zX3RvX2NoZWNrKSB7CiAgICBnZ3Bsb3QoZGF0YSwgYWVzX3N0cmluZyh4ID0gdmFyKSkgKwogICAgICBnZW9tX2JhcihmaWxsID0gInNreWJsdWUiKSArCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiRnJlcXVlbmN5IG9mIiwgdmFyLCAiaW4iLCBkYXRhc2V0X25hbWUpLAogICAgICAgICAgIHggPSB2YXIsIHkgPSAiQ291bnQiKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpIC0+IHAKICAgIHByaW50KHApCiAgfQp9CgojIDIuIFBsb3QgZGlzdHJpYnV0aW9uIGdyYXBocyBmb3IgbnVtZXJpYyB2YXJpYWJsZXMKcGxvdF9kaXN0cmlidXRpb25fZ3JhcGhzIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGFzZXRfbmFtZSkgewogIGZvciAodmFyIGluIG51bWVyaWNhbF92YXJpYWJsZSkgewogICAgZ2dwbG90KGRhdGEsIGFlc19zdHJpbmcoeCA9IHZhcikpICsKICAgICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImxpZ2h0Z3JlZW4iLCBjb2xvciA9ICJibGFjayIpICsKICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJEaXN0cmlidXRpb24gb2YiLCB2YXIsICJpbiIsIGRhdGFzZXRfbmFtZSksCiAgICAgICAgICAgeCA9IHZhciwgeSA9ICJGcmVxdWVuY3kiKSArCiAgICAgIHRoZW1lX21pbmltYWwoKSAtPiBwCiAgICBwcmludChwKQogIH0KfQoKIyAzLiBQbG90IG1pbiwgbWF4LCBtZWFuLCBtZWRpYW4sIG1vZGUgZm9yIG51bWVyaWMgdmFyaWFibGVzCnBsb3Rfc3RhdGlzdGljc19ncmFwaHMgPC0gZnVuY3Rpb24oZGF0YSwgZGF0YXNldF9uYW1lKSB7CiAgZm9yICh2YXIgaW4gbnVtZXJpY2FsX3ZhcmlhYmxlKSB7CiAgICB2YXJfZGF0YSA8LSBkYXRhW1t2YXJdXQogICAgdmFyX2RhdGEgPC0gdmFyX2RhdGFbIWlzLm5hKHZhcl9kYXRhKV0gICMgUmVtb3ZlIE5BcwogICAgCiAgICBtaW5fdmFsIDwtIG1pbih2YXJfZGF0YSkKICAgIG1heF92YWwgPC0gbWF4KHZhcl9kYXRhKQogICAgbWVhbl92YWwgPC0gbWVhbih2YXJfZGF0YSkKICAgIG1lZGlhbl92YWwgPC0gbWVkaWFuKHZhcl9kYXRhKQogICAgbW9kZV92YWwgPC0gbWZ2KHZhcl9kYXRhKSAgIyBNb3N0IGZyZXF1ZW50IHZhbHVlIChtb2RlKQoKICAgIGdncGxvdChkYXRhLCBhZXNfc3RyaW5nKHggPSB2YXIpKSArCiAgICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCwgZmlsbCA9ICJsaWdodGdyZXkiLCBjb2xvciA9ICJibGFjayIpICsKICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWluX3ZhbCwgY29sb3IgPSAiYmx1ZSIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWF4X3ZhbCwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEsIHNob3cubGVnZW5kID0gVFJVRSkgKwogICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuX3ZhbCwgY29sb3IgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gMSwgc2hvdy5sZWdlbmQgPSBUUlVFKSArCiAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbl92YWwsIGNvbG9yID0gInB1cnBsZSIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbW9kZV92YWwsIGNvbG9yID0gIm9yYW5nZSIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJNaW4vTWF4L01lYW4vTWVkaWFuL01vZGUgZm9yIiwgdmFyLCAiaW4iLCBkYXRhc2V0X25hbWUpLAogICAgICAgICAgIHggPSB2YXIsIHkgPSAiRnJlcXVlbmN5IikgKwogICAgICB0aGVtZV9taW5pbWFsKCkgLT4gcAogICAgcHJpbnQocCkKICB9Cn0KCiMgUnVuIGZvciBXZWVrZW5kcwpjYXQoIlBsb3R0aW5nIGZvciBXZWVrZW5kcyBEYXRhc2V0Li4uXG4iKQpwbG90X2ZyZXFfZ3JhcGhzKHdlZWtlbmRzLCAiV2Vla2VuZHMiKQpwbG90X2Rpc3RyaWJ1dGlvbl9ncmFwaHMod2Vla2VuZHMsICJXZWVrZW5kcyIpCnBsb3Rfc3RhdGlzdGljc19ncmFwaHMod2Vla2VuZHMsICJXZWVrZW5kcyIpCgojIFJ1biBmb3IgV2Vla2RheXMKY2F0KCJQbG90dGluZyBmb3IgV2Vla2RheXMgRGF0YXNldC4uLlxuIikKcGxvdF9mcmVxX2dyYXBocyh3ZWVrZGF5cywgIldlZWtkYXlzIikKcGxvdF9kaXN0cmlidXRpb25fZ3JhcGhzKHdlZWtkYXlzLCAiV2Vla2RheXMiKQpwbG90X3N0YXRpc3RpY3NfZ3JhcGhzKHdlZWtkYXlzLCAiV2Vla2RheXMiKQpgYGAKCmBgYHtyfQp3ZWVrZW5kc19wcml2YXRlIDwtIHdlZWtlbmRzICU+JSBmaWx0ZXIocm9vbV90eXBlID09ICJQcml2YXRlIHJvb20iKQp3ZWVrZW5kc19zaGFyZWQgPC0gd2Vla2VuZHMgJT4lIGZpbHRlcihyb29tX3R5cGUgPT0gIlNoYXJlZCByb29tIikKd2Vla2VuZHNfZW50aXJlIDwtIHdlZWtlbmRzICU+JSBmaWx0ZXIocm9vbV90eXBlID09ICJFbnRpcmUgaG9tZS9hcHQiKQoKd2Vla2RheXNfcHJpdmF0ZSA8LSB3ZWVrZGF5cyAlPiUgZmlsdGVyKHJvb21fdHlwZSA9PSAiUHJpdmF0ZSByb29tIikKd2Vla2RheXNfc2hhcmVkIDwtIHdlZWtkYXlzICU+JSBmaWx0ZXIocm9vbV90eXBlID09ICJTaGFyZWQgcm9vbSIpCndlZWtkYXlzX2VudGlyZSA8LSB3ZWVrZGF5cyAlPiUgZmlsdGVyKHJvb21fdHlwZSA9PSAiRW50aXJlIGhvbWUvYXB0IikKCiMgMi4gUGxvdCBoaXN0b2dyYW0gZm9yIFByaXZhdGUgUm9vbQpnZ3Bsb3Qod2Vla2VuZHNfcHJpdmF0ZSwgYWVzKHggPSByZWFsU3VtKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgcmVhbFN1bSAtIFByaXZhdGUgUm9vbSIsCiAgICAgICB4ID0gIlByaWNlIChyZWFsU3VtKSIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIDMuIFBsb3QgaGlzdG9ncmFtIGZvciBTaGFyZWQgUm9vbQpnZ3Bsb3Qod2Vla2VuZHNfc2hhcmVkLCBhZXMoeCA9IHJlYWxTdW0pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwLCBmaWxsID0gImxpZ2h0Y29yYWwiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiByZWFsU3VtIC0gU2hhcmVkIFJvb20iLAogICAgICAgeCA9ICJQcmljZSAocmVhbFN1bSkiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyA0LiBQbG90IGhpc3RvZ3JhbSBmb3IgRW50aXJlIEhvbWUvQXB0CmdncGxvdCh3ZWVrZW5kc19lbnRpcmUsIGFlcyh4ID0gcmVhbFN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAsIGZpbGwgPSAibGlnaHRncmVlbiIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHJlYWxTdW0gLSBFbnRpcmUgSG9tZS9BcHQiLAogICAgICAgeCA9ICJQcmljZSAocmVhbFN1bSkiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyA1LiBQbG90IGhpc3RvZ3JhbSBmb3IgUHJpdmF0ZSBSb29tX3dlZWtkYXkKZ2dwbG90KHdlZWtkYXlzX3ByaXZhdGUsIGFlcyh4ID0gcmVhbFN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAsIGZpbGwgPSAic2t5Ymx1ZSIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHJlYWxTdW0gLSBQcml2YXRlIFJvb21fd2Vla2RheSIsCiAgICAgICB4ID0gIlByaWNlIChyZWFsU3VtKSIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIDYuIFBsb3QgaGlzdG9ncmFtIGZvciBTaGFyZWQgUm9vbV93ZWVrZGF5CmdncGxvdCh3ZWVrZGF5c19zaGFyZWQsIGFlcyh4ID0gcmVhbFN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAsIGZpbGwgPSAibGlnaHRjb3JhbCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHJlYWxTdW0gLSBTaGFyZWQgUm9vbV93ZWVrZGF5IiwKICAgICAgIHggPSAiUHJpY2UgKHJlYWxTdW0pIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgNy4gUGxvdCBoaXN0b2dyYW0gZm9yIEVudGlyZSBIb21lL0FwdF93ZWVrZGF5CmdncGxvdCh3ZWVrZGF5c19lbnRpcmUsIGFlcyh4ID0gcmVhbFN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAsIGZpbGwgPSAibGlnaHRncmVlbiIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHJlYWxTdW0gLSBFbnRpcmUgSG9tZS9BcHRfd2Vla2RheSIsCiAgICAgICB4ID0gIlByaWNlIChyZWFsU3VtKSIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CiMgVmlvbGluIHBsb3QgCmdncGxvdCh3ZWVrZW5kcywgYWVzKHggPSByb29tX3R5cGUsIHkgPSByZWFsU3VtKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAibGlnaHRncmVlbiIpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGZpbGwgPSAid2hpdGUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb24gKHJlYWxTdW0pIGJ5IFJvb20gVHlwZSAoVmlvbGluIFBsb3QpIiwKICAgICAgIHggPSAiUm9vbSBUeXBlIiwgeSA9ICJQcmljZSAocmVhbFN1bSkiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIFZpb2xpbiBwbG90IApnZ3Bsb3Qod2Vla2RheXMsIGFlcyh4ID0gcm9vbV90eXBlLCB5ID0gcmVhbFN1bSkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gImxpZ2h0Z3JlZW4iKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBmaWxsID0gIndoaXRlIikgKwogIGxhYnModGl0bGUgPSAiUHJpY2UgRGlzdHJpYnV0aW9uIChyZWFsU3VtKSBieSBSb29tIFR5cGUgKFZpb2xpbiBQbG90KV93ZWVrZGF5cyIsCiAgICAgICB4ID0gIlJvb20gVHlwZSIsIHkgPSAiUHJpY2UgKHJlYWxTdW0pIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpgYGB7cn0KZ2dwbG90KHdlZWtlbmRzLCBhZXMoeCA9IHJvb21fdHlwZSwgeSA9IHJlYWxTdW0pKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb24gKHJlYWxTdW0pIGJ5IFJvb20gVHlwZSIsCiAgICAgICB4ID0gIlJvb20gVHlwZSIsIHkgPSAiUHJpY2UgKHJlYWxTdW0pIikgKwogIHRoZW1lX21pbmltYWwoKQoKZ2dwbG90KHdlZWtkYXlzLCBhZXMoeCA9IHJvb21fdHlwZSwgeSA9IHJlYWxTdW0pKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb24gKHJlYWxTdW0pIGJ5IFJvb20gVHlwZV93ZWVrZGF5cyIsCiAgICAgICB4ID0gIlJvb20gVHlwZSIsIHkgPSAiUHJpY2UgKHJlYWxTdW0pIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpwcmVkaWN0X2RhdGEgPC0gZGF0YS5mcmFtZShyb29tX3R5cGUgPSAiUHJpdmF0ZSByb29tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbV9zaGFyZWQgPSAiRmFsc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb29tX3ByaXZhdGUgPSAiVHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcnNvbl9jYXBhY2l0eSA9ICIyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGkgPSAiMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlZHJvb21zID0gIjEiLAogICAgICAgICAgICAgICAgICAgICBob3N0X2lzX3N1cGVyaG9zdCA9ICJUcnVlIiwKICAgICAgICAgICAgICAgICAgICAgY2xlYW5saW5lc3NfcmF0aW5nID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIGd1ZXN0X3NhdGlzZmFjdGlvbl9vdmVyYWxsID0gOTgsCiAgICAgICAgICAgICAgICAgICAgIGRpc3QgPSA0LjMyODA0MTAsCiAgICAgICAgICAgICAgICAgICAgIGF0dHJfaW5kZXggPSA3NC4yMzAwMiwKICAgICAgICAgICAgICAgICAgICAgcmVzdF9pbmRleCA9IDE3Ni44Njc5MykKCnByZWRpY3RfcmVhbFN1bSA8LSBwcmVkaWN0KHdlZWtlbmRzX21vZGVsLCBuZXdkYXRhID0gcHJlZGljdF9kYXRhKQoKY2F0KCJQcmVkaWN0ZWQgcHJpY2UgZm9yIGxpc3Rpbmcgd2l0aCBnaXZlbiBhdHRyaWJ1dGUgdmFsdWVzIGlzOiAkIiwgcm91bmQocHJlZGljdF9yZWFsU3VtLCAyKSkKYGBgCgpgYGB7cn0KcHJlZGljdF9kYXRhMSA8LSBkYXRhLmZyYW1lKHJvb21fdHlwZSA9ICJQcml2YXRlIHJvb20iLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb29tX3NoYXJlZCA9ICJGYWxzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvb21fcHJpdmF0ZSA9ICJUcnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVyc29uX2NhcGFjaXR5ID0gIjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aSA9ICIxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVkcm9vbXMgPSAiMiIsCiAgICAgICAgICAgICAgICAgICAgIGhvc3RfaXNfc3VwZXJob3N0ID0gIkZhbHNlIiwKICAgICAgICAgICAgICAgICAgICAgY2xlYW5saW5lc3NfcmF0aW5nID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIGd1ZXN0X3NhdGlzZmFjdGlvbl9vdmVyYWxsID0gMTAwLAogICAgICAgICAgICAgICAgICAgICBkaXN0ID0gNS4zMjYwNDIwLAogICAgICAgICAgICAgICAgICAgICBhdHRyX2luZGV4ID0gNjQuOTM4ODIsCiAgICAgICAgICAgICAgICAgICAgIHJlc3RfaW5kZXggPSAxNzguOTY2NDMpCgpwcmVkaWN0X3JlYWxTdW0xIDwtIHByZWRpY3Qod2Vla2VuZHNfbW9kZWwsIG5ld2RhdGEgPSBwcmVkaWN0X2RhdGExKQoKY2F0KCJQcmVkaWN0ZWQgcHJpY2UgZm9yIGxpc3Rpbmcgd2l0aCBnaXZlbiBhdHRyaWJ1dGUgdmFsdWVzIGlzOiAkIiwgcm91bmQocHJlZGljdF9yZWFsU3VtMSwgMikpCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuCgpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuCg==