sRNA
Load count data
Load in the sRNA count matrix generated using ShortStack 4.1.0. Keep in mind this data includes counts of all sRNAs, not just miRNAs
# Read in sRNA counts data
Apul_counts_sRNA_data_OG <- read_delim("../../../deep-dive/D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/Counts.txt", delim="\t")
head(Apul_counts_sRNA_data_OG)
# A tibble: 6 × 8
Coords Name MIRNA sRNA-ACR-140-S1-TP2-…¹ sRNA-ACR-145-S1-TP2-…²
<chr> <chr> <chr> <dbl> <dbl>
1 NC_058066.1:152483-… Clus… N 2 131
2 NC_058066.1:161064-… Clus… N 57 48
3 NC_058066.1:172073-… Clus… N 36 31
4 NC_058066.1:203242-… Clus… N 14 28
5 NC_058066.1:204535-… Clus… N 3 234
6 NC_058066.1:205745-… Clus… N 914 432
# ℹ abbreviated names: ¹`sRNA-ACR-140-S1-TP2-fastp-adapters-polyG-31bp-merged`,
# ²`sRNA-ACR-145-S1-TP2-fastp-adapters-polyG-31bp-merged`
# ℹ 3 more variables:
# `sRNA-ACR-150-S1-TP2-fastp-adapters-polyG-31bp-merged` <dbl>,
# `sRNA-ACR-173-S1-TP2-fastp-adapters-polyG-31bp-merged` <dbl>,
# `sRNA-ACR-178-S1-TP2-fastp-adapters-polyG-31bp-merged` <dbl>
Count data munging
Apul_counts_sRNA <- Apul_counts_sRNA_data_OG
# Remove excess portions of sample column names to just "sample###"
colnames(Apul_counts_sRNA) <- sub("-S1-TP2-fastp-adapters-polyG-31bp-merged", "", colnames(Apul_counts_sRNA))
colnames(Apul_counts_sRNA) <- sub("sRNA-ACR-", "sample", colnames(Apul_counts_sRNA))
# Keep just the counts and cluster names
Apul_counts_sRNA <- Apul_counts_sRNA %>% select("sample140", "sample145", "sample150", "sample173", "sample178", "Name")
# I'm not going to be doing any removal of low-count sRNAs for now
# Make the cluster names our new row names
Apul_counts_sRNA <- Apul_counts_sRNA %>% column_to_rownames(var = "Name")
write.table(Apul_counts_sRNA, file = "../output/03.1-Apul-sRNA-summary/Apul_sRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)
head(Apul_counts_sRNA)
sample140 sample145 sample150 sample173 sample178
Cluster_1 2 131 2 1 4
Cluster_2 57 48 219 32 193
Cluster_3 36 31 0 36 2
Cluster_4 14 28 3 17 38
Cluster_5 3 234 17 13 46
Cluster_6 914 432 78 247 259
Expression levels
Plot histograms of the expression levels in each sample
# Melt the count matrix into long format
Apul_counts_sRNA_melted <- melt(Apul_counts_sRNA, variable.name = "sample", value.name = "counts")
# Plot the expression level histograms for each sample
ggplot(Apul_counts_sRNA_melted, aes(x = counts)) +
geom_histogram(binwidth = 1, fill = "#408EC6", color = "black") +
scale_x_log10() + # Optional: Log-transform the x-axis for better visualization
facet_wrap(~sample, scales = "free_y") +
labs(title = "Gene Expression Level Histogram for Each Sample",
x = "Expression Level (Counts)",
y = "Frequency") +
theme_minimal()
Transcript counts
First let’s check the total number of transcripts in each sample – keep in mind this expression data has not been normalized yet, so there may be different totals for each sample
# Calculate the total number of transcripts for each sample
total_transcripts <- colSums(Apul_counts_sRNA)
# Create a data frame for plotting
total_transcripts_df <- data.frame(sample = names(total_transcripts),
totals = total_transcripts)
# Plot the total number of transcripts for each sample
ggplot(total_transcripts_df, aes(x = sample, y = totals)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of Transcripts per Sample",
x = "Sample",
y = "Total Transcripts") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
Now let’s check the number of unique transcripts in each sample – that is, how many unique sRNAs are expressed in each sample? This should be pretty much the same across samples, even without normalization.
# Calculate the number of unique transcripts (non-zero counts) for each sample
unique_transcripts <- colSums(Apul_counts_sRNA > 0)
# Create a data frame for plotting
unique_transcripts_df <- data.frame(sample = names(unique_transcripts),
uniques = unique_transcripts)
# Plot the total number of unique transcripts for each sample
ggplot(unique_transcripts_df, aes(x = sample, y = uniques)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of Unique Expressed Transcripts per Sample",
x = "Sample",
y = "Unique Transcripts") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
miRNA
Expression levels
Plot histograms of the expression levels in each sample
# Melt the count matrix into long format
Apul_counts_miRNA_melted <- melt(Apul_counts_miRNA, variable.name = "sample", value.name = "counts")
# Plot the expression level histograms for each sample
ggplot(Apul_counts_miRNA_melted, aes(x = counts)) +
geom_histogram(binwidth = 1, fill = "#408EC6", color = "black") +
scale_x_log10() + # Optional: Log-transform the x-axis for better visualization
facet_wrap(~sample, scales = "free_y") +
labs(title = "Gene Expression Level Histogram for Each Sample",
x = "Expression Level (Counts)",
y = "Frequency") +
theme_minimal()
miRNA counts
First let’s check the total number of miRNAs in each sample – keep in mind this expression data has not been normalized yet, so there may be different totals for each sample
# Calculate the total number of transcripts for each sample
total_miRNA <- colSums(Apul_counts_miRNA)
# Create a data frame for plotting
total_miRNA_df <- data.frame(sample = names(total_miRNA),
totals = total_miRNA)
# Plot the total number of transcripts for each sample
ggplot(total_miRNA_df, aes(x = sample, y = totals)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of miRNAs per Sample",
x = "Sample",
y = "Total miRNAs") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
Now let’s check the number of unique miRNAs in each sample – This should be pretty much the same across samples, even without normalization.
# Calculate the number of unique transcripts (non-zero counts) for each sample
unique_miRNA <- colSums(Apul_counts_miRNA > 0)
# Create a data frame for plotting
unique_miRNA_df <- data.frame(sample = names(unique_miRNA),
uniques = unique_miRNA)
# Plot the total number of unique transcripts for each sample
ggplot(unique_miRNA_df, aes(x = sample, y = uniques)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of Unique Expressed miRNAs per Sample",
x = "Sample",
y = "Unique miRNA") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
Heatmap
pheatmap(Apul_counts_miRNA,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
color = colorRampPalette(c("blue", "white", "red"))(50),
fontsize_row = 8,
fontsize_col = 8)
Well… there’s like 2 miRNAs with much higher expression than the others, which is making visualizing relative differences difficult. Let’s redo the heatmap, normalizing each row to view relative difference in expression between samples (scale='row'
)
pheatmap(Apul_counts_miRNA,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
scale = 'row',
color = colorRampPalette(c("blue", "white", "red"))(50),
fontsize_row = 8,
fontsize_col = 8)
Normalized sRNA counts
Normalize counts with DESeq2
Plot unnormalized sRNA data
Apul_counts_sRNA %>%
select(-Name) %>%
pivot_longer( cols = everything(), names_to = "sample", values_to = "count") %>%
ggplot(., aes(x = sample, y = count)) +
geom_violin() +
geom_point(alpha = 0.2) +
theme_minimal() +
labs(title = "Unnormalized sRNA counts",
x = "Sample",
y = "count")
DESeq object
# Calculate DESeq object
Apul_counts_sRNA_rowNames <- Apul_counts_sRNA %>% column_to_rownames(var = "Name")
dds_Apul_sRNA <- DESeqDataSetFromMatrix(countData = Apul_counts_sRNA_rowNames,
colData = Apul_metadata_sRNA,
design = ~ 1)
# Run differential expression analysis
# (Note that this DESeq() function runs all necessary steps, including data normalization,
# estimating size factors, estimating dispersions, gene-wise dispersion estimates, mean-dispersion
# relationship, final dispersion estimates, fitting model, and testing)
# Using design = ~1 because we don't have treatment groups
dds_Apul_sRNA <- DESeq(dds_Apul_sRNA)
It’s worth noting here that I’m actually going to be doing two different types of transformation on the counts data, which serve different purposes.
First is normalizing the transcript counts, which adjusts for differences in library size or sequencing depth, but retains count-like properties. Normalized counts are most useful for things like visualizing expression levels and differential expression analysis.
Second is variance stabilizing the counts data, which aims to make the variance of the transformed data approximately independent of the mean, reducing heteroscedasticity (the relationship between variance and mean) and “smoothing” out the variance at low counts. Notably, the transformed data is no longer on the original count scale. The transformation makes the variance roughly constant across the range of counts, which makes it easier to interpret patterns in the data visually. Variance stabilized data is most useful for exploratory data analysis, like PCA, clustering, and heatmaps, and is also the transformation we’ll want to use before WGCNA.
# extract normalized counts
# (normalization is automatically performed by deseq2)
Apul_counts_sRNA_norm <- counts(dds_Apul_sRNA, normalized=TRUE) %>% data.frame()
write.table(Apul_counts_sRNA_norm, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_sRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)
# variance stabilized data
vsd_Apul_sRNA <- varianceStabilizingTransformation(dds_Apul_sRNA, blind=TRUE)
wpn_vsd_Apul_sRNA <- getVarianceStabilizedData(dds_Apul_sRNA)
rv_wpn_Apul_sRNA <- rowVars(wpn_vsd_Apul_sRNA, useNames=TRUE)
Apul_counts_sRNA_vsd <- data.frame(wpn_vsd_Apul_sRNA)
write.table(Apul_counts_sRNA_vsd, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_sRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
q75_wpn_Apul_sRNA <- quantile(rowVars(wpn_vsd_Apul_sRNA, useNames=TRUE), .75) # 75th quantile variability
Apul_counts_sRNA_vsd_q75 <- wpn_vsd_Apul_sRNA[ rv_wpn_Apul_sRNA > q75_wpn_Apul_sRNA, ] %>% data.frame # filter to retain only the most variable genes
write.table(Apul_counts_sRNA_vsd_q75, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_sRNA_variancestabilized_q75.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
q95_wpn_Apul_sRNA <- quantile(rowVars(wpn_vsd_Apul_sRNA, useNames=TRUE), .95) # 95th quantile variability
Apul_counts_sRNA_vsd_q95 <- wpn_vsd_Apul_sRNA[ rv_wpn_Apul_sRNA > q95_wpn_Apul_sRNA, ] %>% data.frame # filter to retain only the most variable genes
write.table(Apul_counts_sRNA_vsd_q95, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_sRNA_variancestabilized_q95.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
Plot normalized data
Apul_counts_sRNA_norm_long <- Apul_counts_sRNA_norm %>%
mutate(
Gene_id = row.names(Apul_counts_sRNA_norm)
) %>%
pivot_longer(-Gene_id)
Apul_counts_sRNA_norm_long %>%
ggplot(., aes(x = name, y = value)) +
geom_violin() +
geom_point() +
theme_bw() +
theme(
axis.text.x = element_text( angle = 90)
) +
ylim(0, NA) +
labs(
title = "Normalized Expression",
x = "Sample",
y = "Normalized counts"
)
Plot variance stabilized data
Apul_counts_sRNA_vsd_long <- Apul_counts_sRNA_vsd %>%
mutate(
Gene_id = row.names(Apul_counts_sRNA_vsd)
) %>%
pivot_longer(-Gene_id)
Apul_counts_sRNA_vsd_long %>%
ggplot(., aes(x = name, y = value)) +
geom_violin() +
geom_point() +
theme_bw() +
theme(
axis.text.x = element_text( angle = 90)
) +
ylim(0, NA) +
labs(
title = "Variance Stabilized Expression",
x = "Sample",
y = "Variance stabilized data"
)
Normalized expression levels
Plot histograms of the normalized expression levels in each sample
# Melt the count matrix into long format
Apul_counts_norm_melted <- melt(Apul_counts_sRNA_norm, variable.name = "sample", value.name = "counts")
# Plot the expression level histograms for each sample
ggplot(Apul_counts_norm_melted, aes(x = counts)) +
geom_histogram(binwidth = 1, fill = "#408EC6", color = "black") +
scale_x_log10() + # Optional: Log-transform the x-axis for better visualization
facet_wrap(~sample, scales = "free_y") +
labs(title = "Gene Expression Level Histogram for Each Sample",
x = "Expression Level (Counts)",
y = "Frequency") +
theme_minimal()
Normalized transcript counts
Check the total number of transcripts in each sample – now that we’ve normalized the data these totals should be similar
# Calculate the total number of transcripts for each sample
total_transcripts_norm <- colSums(Apul_counts_sRNA_norm)
# Create a data frame for plotting
total_transcripts_norm_df <- data.frame(sample = names(total_transcripts_norm),
totals = total_transcripts_norm)
# Plot the total number of transcripts for each sample
ggplot(total_transcripts_norm_df, aes(x = sample, y = totals)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of Transcripts per Sample",
x = "Sample",
y = "Total Transcripts") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
PCA of variance stabilized data
plotPCA(vsd_Apul_sRNA, intgroup="Sample")
Sample clustering
sample_dists <- dist(t(assay(vsd_Apul_sRNA)))
pheatmap(as.matrix(sample_dists), clustering_distance_rows = "euclidean",
clustering_distance_cols = "euclidean", main="Sample Clustering")
Heatmaps
Of most variable variance stabilized sRNA transcripts
# 75th quantile
heat_colors <- rev(brewer.pal(12, "RdYlBu"))
pheatmap(Apul_counts_sRNA_vsd_q75,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
color = heat_colors,
scale="row")
# 95th quantile
pheatmap(Apul_counts_sRNA_vsd_q95,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
color = heat_colors,
scale="row")
Normalized miRNA counts
Isolate normalized/vsd miRNA
Apul_counts_sRNA_norm$Name <- rownames(Apul_counts_sRNA_norm)
Apul_counts_miRNA_norm <- left_join(Apul_metadata_miRNA, Apul_counts_sRNA_norm, by = c("Name" = "Name")) %>%
column_to_rownames(var="given_miRNA_name") %>%
select(starts_with("sample"))
write.table(Apul_counts_miRNA_norm, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_miRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
Apul_counts_sRNA_vsd$Name <- rownames(Apul_counts_sRNA_vsd)
Apul_counts_miRNA_vsd <- left_join(Apul_metadata_miRNA, Apul_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
column_to_rownames(var="given_miRNA_name") %>%
select(starts_with("sample"))
write.table(Apul_counts_miRNA_vsd, file = "../output/03.1-Apul-sRNA-summary/Apul_counts_miRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
Normalized expression levels
Plot histograms of the normalized expression levels in each sample
# Melt the count matrix into long format
Apul_counts_miRNA_norm_melted <- melt(Apul_counts_miRNA_norm, variable.name = "sample", value.name = "counts")
# Plot the expression level histograms for each sample
ggplot(Apul_counts_miRNA_norm_melted, aes(x = counts)) +
geom_histogram(binwidth = 1, fill = "#408EC6", color = "black") +
scale_x_log10() + # Optional: Log-transform the x-axis for better visualization
facet_wrap(~sample, scales = "free_y") +
labs(title = "Gene Expression Level Histogram for Each Sample",
x = "Expression Level (Counts)",
y = "Frequency") +
theme_minimal()
Normalized transcript counts
Check the total number of transcripts in each sample – now that we’ve normalized the data these totals should be similar
# Calculate the total number of transcripts for each sample
total_transcripts_miRNA_norm <- colSums(Apul_counts_miRNA_norm)
# Create a data frame for plotting
total_transcripts_miRNA_norm_df <- data.frame(sample = names(total_transcripts_miRNA_norm),
totals = total_transcripts_miRNA_norm)
# Plot the total number of transcripts for each sample
ggplot(total_transcripts_miRNA_norm_df, aes(x = sample, y = totals)) +
geom_bar(stat = "identity", fill = "#408EC6", color = "black") +
labs(title = "Total Number of miRNA Transcripts per Sample",
x = "Sample",
y = "Total Transcripts") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotate x-axis labels for readability
Heatmap
Of all miRNAs
heat_colors <- rev(brewer.pal(12, "RdYlBu"))
pheatmap(Apul_counts_miRNA_vsd,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
color = heat_colors,
scale="row")
LS0tCnRpdGxlOiAiMDMuMS1BcHVsLXNSTkEtc3VtbWFyeSIKYXV0aG9yOiAiS2F0aGxlZW4gRHVya2luIgpkYXRlOiAiMjAyNC0wOS0wNSIKYWx3YXlzX2FsbG93X2h0bWw6IHRydWUKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGh0bWxfcHJldmlldzogdHJ1ZSAKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBUUlVFLCAgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKR2VuZSBleHByZXNzaW9uIHN1bW1hcnkgZm9yICpBY3JvcG9yYSBwdWxjaHJhKiBzUk5BLXNlcSBkYXRhLgoKLSAgIHRyaW1tZWQgcmVhZHMgZ2VuZXJhdGVkIGluIGBkZWVwLWRpdmVgIHByb2plY3QKCi0gICBSZWFkcyBhbGlnbmVkIHRvICpBY3JvcG9yYSBtZWFuZHJpbmEqIGdlbm9tZSAKCiMjIyBJbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgaW5sY3VkZSA9IFRSVUV9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KERFU2VxMikKYGBgCgoKIyBzUk5BCgojIyBMb2FkIGNvdW50IGRhdGEKCkxvYWQgaW4gdGhlIHNSTkEgY291bnQgbWF0cml4IGdlbmVyYXRlZCB1c2luZyBTaG9ydFN0YWNrIDQuMS4wLiBLZWVwIGluIG1pbmQgdGhpcyBkYXRhIGluY2x1ZGVzIGNvdW50cyBvZiBhbGwgc1JOQXMsIG5vdCBqdXN0IG1pUk5BcwoKYGBge3IgbG9hZC1zUk5BLWNvdW50c30KIyBSZWFkIGluIHNSTkEgY291bnRzIGRhdGEKQXB1bF9jb3VudHNfc1JOQV9kYXRhX09HIDwtIHJlYWRfZGVsaW0oIi4uLy4uLy4uL2RlZXAtZGl2ZS9ELUFwdWwvb3V0cHV0LzEzLjIuMS1BcHVsLXNSTkFzZXEtU2hvcnRTdGFjay0zMWJwLWZhc3RwLW1lcmdlZC1jbmlkYXJpYW5fbWlSQmFzZS9TaG9ydFN0YWNrX291dC9Db3VudHMudHh0IiwgZGVsaW09Ilx0IikgCmhlYWQoQXB1bF9jb3VudHNfc1JOQV9kYXRhX09HKQpgYGAKCiMjIENvdW50IGRhdGEgbXVuZ2luZwoKYGBge3Igc1JOQS1jb3VudC1kYXRhLW11bmdpbmd9CkFwdWxfY291bnRzX3NSTkEgPC0gQXB1bF9jb3VudHNfc1JOQV9kYXRhX09HCgojIFJlbW92ZSBleGNlc3MgcG9ydGlvbnMgb2Ygc2FtcGxlIGNvbHVtbiBuYW1lcyB0byBqdXN0ICJzYW1wbGUjIyMiCmNvbG5hbWVzKEFwdWxfY291bnRzX3NSTkEpIDwtIHN1YigiLVMxLVRQMi1mYXN0cC1hZGFwdGVycy1wb2x5Ry0zMWJwLW1lcmdlZCIsICIiLCBjb2xuYW1lcyhBcHVsX2NvdW50c19zUk5BKSkKY29sbmFtZXMoQXB1bF9jb3VudHNfc1JOQSkgPC0gc3ViKCJzUk5BLUFDUi0iLCAic2FtcGxlIiwgY29sbmFtZXMoQXB1bF9jb3VudHNfc1JOQSkpCgojIEtlZXAganVzdCB0aGUgY291bnRzIGFuZCBjbHVzdGVyIG5hbWVzCkFwdWxfY291bnRzX3NSTkEgPC0gQXB1bF9jb3VudHNfc1JOQSAlPiUgc2VsZWN0KCJzYW1wbGUxNDAiLCAic2FtcGxlMTQ1IiwgInNhbXBsZTE1MCIsICJzYW1wbGUxNzMiLCAic2FtcGxlMTc4IiwgIk5hbWUiKQoKIyBJJ20gbm90IGdvaW5nIHRvIGJlIGRvaW5nIGFueSByZW1vdmFsIG9mIGxvdy1jb3VudCBzUk5BcyBmb3Igbm93CgojIE1ha2UgdGhlIGNsdXN0ZXIgbmFtZXMgb3VyIG5ldyByb3cgbmFtZXMKQXB1bF9jb3VudHNfc1JOQSA8LSBBcHVsX2NvdW50c19zUk5BICU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQoKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfc1JOQSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1BcHVsLXNSTkEtc3VtbWFyeS9BcHVsX3NSTkFfU2hvcnRTdGFja19jb3VudHNfZm9ybWF0dGVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCgpoZWFkKEFwdWxfY291bnRzX3NSTkEpCmBgYAoKCiMjIEV4cHJlc3Npb24gbGV2ZWxzCgpQbG90IGhpc3RvZ3JhbXMgb2YgdGhlIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBleHByZXNzaW9uLWxldmVsLWhpc3RvZ3JhbXN9CiMgTWVsdCB0aGUgY291bnQgbWF0cml4IGludG8gbG9uZyBmb3JtYXQKQXB1bF9jb3VudHNfc1JOQV9tZWx0ZWQgPC0gbWVsdChBcHVsX2NvdW50c19zUk5BLCB2YXJpYWJsZS5uYW1lID0gInNhbXBsZSIsIHZhbHVlLm5hbWUgPSAiY291bnRzIikKCiMgUGxvdCB0aGUgZXhwcmVzc2lvbiBsZXZlbCBoaXN0b2dyYW1zIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QoQXB1bF9jb3VudHNfc1JOQV9tZWx0ZWQsIGFlcyh4ID0gY291bnRzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgICMgT3B0aW9uYWw6IExvZy10cmFuc2Zvcm0gdGhlIHgtYXhpcyBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24KICBmYWNldF93cmFwKH5zYW1wbGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh0aXRsZSA9ICJHZW5lIEV4cHJlc3Npb24gTGV2ZWwgSGlzdG9ncmFtIGZvciBFYWNoIFNhbXBsZSIsCiAgICAgICB4ID0gIkV4cHJlc3Npb24gTGV2ZWwgKENvdW50cykiLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgVHJhbnNjcmlwdCBjb3VudHMKCkZpcnN0IGxldCdzIGNoZWNrIHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgaW4gZWFjaCBzYW1wbGUgLS0ga2VlcCBpbiBtaW5kIHRoaXMgZXhwcmVzc2lvbiBkYXRhIGhhcyAqbm90KiBiZWVuIG5vcm1hbGl6ZWQgeWV0LCBzbyB0aGVyZSBtYXkgYmUgZGlmZmVyZW50IHRvdGFscyBmb3IgZWFjaCBzYW1wbGUKYGBge3IgdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHMgPC0gY29sU3VtcyhBcHVsX2NvdW50c19zUk5BKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp0b3RhbF90cmFuc2NyaXB0c19kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHRvdGFsX3RyYW5zY3JpcHRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF90cmFuc2NyaXB0cykKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodG90YWxfdHJhbnNjcmlwdHNfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgVHJhbnNjcmlwdHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCgpOb3cgbGV0J3MgY2hlY2sgdGhlIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgaW4gZWFjaCBzYW1wbGUgLS0gdGhhdCBpcywgaG93IG1hbnkgdW5pcXVlIHNSTkFzIGFyZSBleHByZXNzZWQgaW4gZWFjaCBzYW1wbGU/IFRoaXMgc2hvdWxkIGJlIHByZXR0eSBtdWNoIHRoZSBzYW1lIGFjcm9zcyBzYW1wbGVzLCBldmVuIHdpdGhvdXQgbm9ybWFsaXphdGlvbi4KCmBgYHtyIHRvdGFsLXVuaXF1ZS10cmFuc2NyaXB0cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHVuaXF1ZSB0cmFuc2NyaXB0cyAobm9uLXplcm8gY291bnRzKSBmb3IgZWFjaCBzYW1wbGUKdW5pcXVlX3RyYW5zY3JpcHRzIDwtIGNvbFN1bXMoQXB1bF9jb3VudHNfc1JOQSA+IDApCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnVuaXF1ZV90cmFuc2NyaXB0c19kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHVuaXF1ZV90cmFuc2NyaXB0cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZXMgPSB1bmlxdWVfdHJhbnNjcmlwdHMpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh1bmlxdWVfdHJhbnNjcmlwdHNfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdW5pcXVlcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVW5pcXVlIEV4cHJlc3NlZCBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVW5pcXVlIFRyYW5zY3JpcHRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAogICAKCiMgbWlSTkEKCiMjIExvYWQgbWlSTkEgbWV0YWRhdGEKClRoZSBTaG9ydFN0YWNrIG91dHB1dCBSZXN1bHRzLnR4dCBpbmNsdWRlcyBhbGwgY2x1c3RlcnMgb2Ygc1JOQSByZWFkcywgaW5jbHVkaW5nIHRob3NlIG5vdCBhbm5vdGF0ZWQgYXMgdmFsaWQgbWlSTkFzLiBOb3cgdGhhdCB3ZSd2ZSBsb29rZWQgYXQgYWxsIHRoZSBzUk5BcyBhIGJpdCwgbGV0J3MgZm9jdXMgaW4gb24gdGhvc2UgY2xhc3NpZmllZCBhcyBtaVJOQXMuCgpgYGB7ciBtaVJOQS1jb3VudC1kYXRhLW11bmdpbmd9CgojIEpvaW4gd2l0aCBmdWxsIG1ldGFkYXRhIHNoZWV0LCB3aGljaCBvbmx5IGNvbnRhaW5zIHZhbGlkIG1pUk5BcwpBcHVsX21ldGFkYXRhX21pUk5BIDwtIHJlYWRfY3N2KCIuLi8uLi8uLi9kZWVwLWRpdmUvREVGLWNyb3NzLXNwZWNpZXMvb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX3Jlc3VsdHNfbWF0dXJlX25hbWVkLmNzdiIpIAoKQXB1bF9jb3VudHNfc1JOQSA8LSByb3duYW1lc190b19jb2x1bW4oQXB1bF9jb3VudHNfc1JOQSwgdmFyID0gIk5hbWUiKQoKQXB1bF9jb3VudHNfbWlSTkEgPC0gbGVmdF9qb2luKEFwdWxfbWV0YWRhdGFfbWlSTkEsIEFwdWxfY291bnRzX3NSTkEsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKQoKIyBLZWVwIGp1c3QgdGhlIGNvdW50cyBhbmQgZ2l2ZW4gbWlSTkEgbmFtZXMgKGUuZy4sIGJhc2VkIG9uIG1hdGNoIHRvIHByZXZpb3VzbHkgZGVzY3JpYmVkIG1pUk5BKQpBcHVsX2NvdW50c19taVJOQSA8LSBBcHVsX2NvdW50c19taVJOQSAlPiUgc2VsZWN0KCJzYW1wbGUxNDAiLCAic2FtcGxlMTQ1IiwgInNhbXBsZTE1MCIsICJzYW1wbGUxNzMiLCAic2FtcGxlMTc4IiwgImdpdmVuX21pUk5BX25hbWUiKQoKIyBNYWtlIHRoZSBtaVJOQSBuYW1lcyBvdXIgbmV3IHJvdyBuYW1lcwpBcHVsX2NvdW50c19taVJOQSA8LSBBcHVsX2NvdW50c19taVJOQSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJnaXZlbl9taVJOQV9uYW1lIikKCmhlYWQoQXB1bF9jb3VudHNfbWlSTkEpCmBgYAoKIyMgRXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgaW4gZWFjaCBzYW1wbGUKCmBgYHtyIG1pUk5BLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19taVJOQV9tZWx0ZWQgPC0gbWVsdChBcHVsX2NvdW50c19taVJOQSwgdmFyaWFibGUubmFtZSA9ICJzYW1wbGUiLCB2YWx1ZS5uYW1lID0gImNvdW50cyIpCgojIFBsb3QgdGhlIGV4cHJlc3Npb24gbGV2ZWwgaGlzdG9ncmFtcyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KEFwdWxfY291bnRzX21pUk5BX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBtaVJOQSBjb3VudHMKCkZpcnN0IGxldCdzIGNoZWNrIHRoZSB0b3RhbCBudW1iZXIgb2YgbWlSTkFzIGluIGVhY2ggc2FtcGxlIC0tIGtlZXAgaW4gbWluZCB0aGlzIGV4cHJlc3Npb24gZGF0YSBoYXMgKm5vdCogYmVlbiBub3JtYWxpemVkIHlldCwgc28gdGhlcmUgbWF5IGJlIGRpZmZlcmVudCB0b3RhbHMgZm9yIGVhY2ggc2FtcGxlCmBgYHtyIG1pUk5BLWNvdW50cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQp0b3RhbF9taVJOQSA8LSBjb2xTdW1zKEFwdWxfY291bnRzX21pUk5BKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp0b3RhbF9taVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHRvdGFsX21pUk5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF9taVJOQSkKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodG90YWxfbWlSTkFfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBtaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIG1pUk5BcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCk5vdyBsZXQncyBjaGVjayB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBtaVJOQXMgaW4gZWFjaCBzYW1wbGUgLS0gVGhpcyBzaG91bGQgYmUgcHJldHR5IG11Y2ggdGhlIHNhbWUgYWNyb3NzIHNhbXBsZXMsIGV2ZW4gd2l0aG91dCBub3JtYWxpemF0aW9uLgoKYGBge3IgdG90YWwtdW5pcXVlLW1pUk5BLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIChub24temVybyBjb3VudHMpIGZvciBlYWNoIHNhbXBsZQp1bmlxdWVfbWlSTkEgPC0gY29sU3VtcyhBcHVsX2NvdW50c19taVJOQSA+IDApCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnVuaXF1ZV9taVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHVuaXF1ZV9taVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZXMgPSB1bmlxdWVfbWlSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh1bmlxdWVfbWlSTkFfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdW5pcXVlcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVW5pcXVlIEV4cHJlc3NlZCBtaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBtaVJOQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIEhlYXRtYXAKCmBgYHtyIG1pUk5BLWhlYXRtYXB9CnBoZWF0bWFwKEFwdWxfY291bnRzX21pUk5BLAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCksCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgIGZvbnRzaXplX2NvbCA9IDgpCmBgYApXZWxsLi4uIHRoZXJlJ3MgbGlrZSAyIG1pUk5BcyB3aXRoIG11Y2ggaGlnaGVyIGV4cHJlc3Npb24gdGhhbiB0aGUgb3RoZXJzLCB3aGljaCBpcyBtYWtpbmcgdmlzdWFsaXppbmcgcmVsYXRpdmUgZGlmZmVyZW5jZXMgZGlmZmljdWx0LiBMZXQncyByZWRvIHRoZSBoZWF0bWFwLCBub3JtYWxpemluZyBlYWNoIHJvdyB0byB2aWV3IHJlbGF0aXZlIGRpZmZlcmVuY2UgaW4gZXhwcmVzc2lvbiBiZXR3ZWVuIHNhbXBsZXMgKGBzY2FsZT0ncm93J2ApCgpgYGB7ciBtaVJOQS1oZWF0bWFwLXJvd3NjYWxlfQpwaGVhdG1hcChBcHVsX2NvdW50c19taVJOQSwKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBzY2FsZSA9ICdyb3cnLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoNTApLAogICAgICAgICBmb250c2l6ZV9yb3cgPSA4LAogICAgICAgICBmb250c2l6ZV9jb2wgPSA4KQpgYGAKCgoKIyBOb3JtYWxpemVkIHNSTkEgY291bnRzCgojIyBOb3JtYWxpemUgY291bnRzIHdpdGggREVTZXEyCgojIyMgUGxvdCB1bm5vcm1hbGl6ZWQgc1JOQSBkYXRhCgpgYGB7ciBwbG90LXVubm9ybWFsaXplZC1zUk5BfQoKQXB1bF9jb3VudHNfc1JOQSAlPiUgCiAgc2VsZWN0KC1OYW1lKSAlPiUKICBwaXZvdF9sb25nZXIoIGNvbHMgPSBldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gInNhbXBsZSIsIHZhbHVlc190byA9ICJjb3VudCIpICU+JQogIGdncGxvdCguLCBhZXMoeCA9IHNhbXBsZSwgeSA9IGNvdW50KSkgKwogIGdlb21fdmlvbGluKCkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC4yKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlVubm9ybWFsaXplZCBzUk5BIGNvdW50cyIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gImNvdW50IikKYGBgCgojIyMgTWV0YWRhdGEKCkRFU2VxMiByZXF1aXJlcyBhIG1ldGFkYXRhIGRhdGEgZnJhbWUgYXMgaW5wdXQuIEkgZG9uJ3QgaGF2ZSBzYW1wbGUgbWV0YWRhdGEgdGhvdWdoIHNvLCBzaW5jZSB3ZSdyZSBqdXN0IGRvaW5nIERFU2VxMiBmb3Igbm9ybWFsaXphdGlvbiBwdXJwb3NlcyAobm90IGFuYWx5c2lzIHB1cnBvc2VzKSwgSSdtIGp1c3QgZ29pbmcgdG8gY3JlYXRlIGEgZHVtbXkgc2hlZXQKCmBgYHtyIG1ha2Utc1JOQS1tZXRhZGF0YS1kYXRhZnJhbWV9CkFwdWxfc2FtcGxlX25hbWVzIDwtIEFwdWxfY291bnRzX3NSTkEgJT4lCiAgc2VsZWN0KC1OYW1lKSAlPiUKICBjb2xuYW1lcygpCgpBcHVsX21ldGFkYXRhX3NSTkEgPC0gZGF0YS5mcmFtZShTYW1wbGUgPSBBcHVsX3NhbXBsZV9uYW1lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNwZWNpZXMgPSByZXAoIkEucHVsY2hyYSIsIDUpKQpyb3duYW1lcyhBcHVsX21ldGFkYXRhX3NSTkEpIDwtIEFwdWxfc2FtcGxlX25hbWVzCgpoZWFkKEFwdWxfbWV0YWRhdGFfc1JOQSkKYGBgCgojIyMgREVTZXEgb2JqZWN0CgpgYGB7ciBtYWtlLXNSTkEtZGVzZXEtb2JqZWN0LCBjYWNoZT1UUlVFfQojIENhbGN1bGF0ZSBERVNlcSBvYmplY3QKQXB1bF9jb3VudHNfc1JOQV9yb3dOYW1lcyA8LSBBcHVsX2NvdW50c19zUk5BICU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQoKZGRzX0FwdWxfc1JOQSA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IEFwdWxfY291bnRzX3NSTkFfcm93TmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBBcHVsX21ldGFkYXRhX3NSTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gMSkgCgojIFJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyAKIyAoTm90ZSB0aGF0IHRoaXMgREVTZXEoKSBmdW5jdGlvbiBydW5zIGFsbCBuZWNlc3Nhcnkgc3RlcHMsIGluY2x1ZGluZyBkYXRhIG5vcm1hbGl6YXRpb24sIAojIGVzdGltYXRpbmcgc2l6ZSBmYWN0b3JzLCBlc3RpbWF0aW5nIGRpc3BlcnNpb25zLCBnZW5lLXdpc2UgZGlzcGVyc2lvbiBlc3RpbWF0ZXMsIG1lYW4tZGlzcGVyc2lvbiAKIyByZWxhdGlvbnNoaXAsIGZpbmFsIGRpc3BlcnNpb24gZXN0aW1hdGVzLCBmaXR0aW5nIG1vZGVsLCBhbmQgdGVzdGluZykKIyBVc2luZyBkZXNpZ24gPSB+MSBiZWNhdXNlIHdlIGRvbid0IGhhdmUgdHJlYXRtZW50IGdyb3VwcwoKZGRzX0FwdWxfc1JOQSA8LSBERVNlcShkZHNfQXB1bF9zUk5BKQpgYGAKCkl0J3Mgd29ydGggbm90aW5nIGhlcmUgdGhhdCBJJ20gYWN0dWFsbHkgZ29pbmcgdG8gYmUgZG9pbmcgdHdvIGRpZmZlcmVudCB0eXBlcyBvZiB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgY291bnRzIGRhdGEsIHdoaWNoIHNlcnZlIGRpZmZlcmVudCBwdXJwb3Nlcy4gCgotIEZpcnN0IGlzICoqbm9ybWFsaXppbmcqKiB0aGUgdHJhbnNjcmlwdCBjb3VudHMsIHdoaWNoIGFkanVzdHMgZm9yIGRpZmZlcmVuY2VzIGluIGxpYnJhcnkgc2l6ZSBvciBzZXF1ZW5jaW5nIGRlcHRoLCBidXQgcmV0YWlucyBjb3VudC1saWtlIHByb3BlcnRpZXMuIE5vcm1hbGl6ZWQgY291bnRzIGFyZSBtb3N0IHVzZWZ1bCBmb3IgdGhpbmdzIGxpa2UgdmlzdWFsaXppbmcgZXhwcmVzc2lvbiBsZXZlbHMgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLgoKLSBTZWNvbmQgaXMgKip2YXJpYW5jZSBzdGFiaWxpemluZyoqIHRoZSBjb3VudHMgZGF0YSwgd2hpY2ggYWltcyB0byBtYWtlIHRoZSB2YXJpYW5jZSBvZiB0aGUgdHJhbnNmb3JtZWQgZGF0YSBhcHByb3hpbWF0ZWx5IGluZGVwZW5kZW50IG9mIHRoZSBtZWFuLCByZWR1Y2luZyBoZXRlcm9zY2VkYXN0aWNpdHkgKHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYW5jZSBhbmQgbWVhbikgYW5kICJzbW9vdGhpbmciIG91dCB0aGUgdmFyaWFuY2UgYXQgbG93IGNvdW50cy4gTm90YWJseSwgdGhlIHRyYW5zZm9ybWVkIGRhdGEgaXMgKm5vIGxvbmdlciBvbiB0aGUgb3JpZ2luYWwgY291bnQgc2NhbGUqLiBUaGUgdHJhbnNmb3JtYXRpb24gbWFrZXMgdGhlIHZhcmlhbmNlIHJvdWdobHkgY29uc3RhbnQgYWNyb3NzIHRoZSByYW5nZSBvZiBjb3VudHMsIHdoaWNoIG1ha2VzIGl0IGVhc2llciB0byBpbnRlcnByZXQgcGF0dGVybnMgaW4gdGhlIGRhdGEgdmlzdWFsbHkuIFZhcmlhbmNlIHN0YWJpbGl6ZWQgZGF0YSBpcyBtb3N0IHVzZWZ1bCBmb3IgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcywgbGlrZSBQQ0EsIGNsdXN0ZXJpbmcsIGFuZCBoZWF0bWFwcywgYW5kIGlzIGFsc28gdGhlIHRyYW5zZm9ybWF0aW9uIHdlJ2xsIHdhbnQgdG8gdXNlIGJlZm9yZSBXR0NOQS4KCmBgYHtyIGdldC1ub3JtYWxpemVkLXNSTkEtY291bnRzLCBjYWNoZT1UUlVFfQojIGV4dHJhY3Qgbm9ybWFsaXplZCBjb3VudHMKIyAobm9ybWFsaXphdGlvbiBpcyBhdXRvbWF0aWNhbGx5IHBlcmZvcm1lZCBieSBkZXNlcTIpCkFwdWxfY291bnRzX3NSTkFfbm9ybSA8LSBjb3VudHMoZGRzX0FwdWxfc1JOQSwgbm9ybWFsaXplZD1UUlVFKSAlPiUgZGF0YS5mcmFtZSgpCgp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zUk5BX25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtQXB1bC1zUk5BLXN1bW1hcnkvQXB1bF9jb3VudHNfc1JOQV9ub3JtYWxpemVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCgoKIyB2YXJpYW5jZSBzdGFiaWxpemVkIGRhdGEKdnNkX0FwdWxfc1JOQSA8LSB2YXJpYW5jZVN0YWJpbGl6aW5nVHJhbnNmb3JtYXRpb24oZGRzX0FwdWxfc1JOQSwgYmxpbmQ9VFJVRSkKd3BuX3ZzZF9BcHVsX3NSTkEgPC0gZ2V0VmFyaWFuY2VTdGFiaWxpemVkRGF0YShkZHNfQXB1bF9zUk5BKQpydl93cG5fQXB1bF9zUk5BIDwtIHJvd1ZhcnMod3BuX3ZzZF9BcHVsX3NSTkEsIHVzZU5hbWVzPVRSVUUpCgpBcHVsX2NvdW50c19zUk5BX3ZzZCA8LSBkYXRhLmZyYW1lKHdwbl92c2RfQXB1bF9zUk5BKQp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zUk5BX3ZzZCwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1BcHVsLXNSTkEtc3VtbWFyeS9BcHVsX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCgpxNzVfd3BuX0FwdWxfc1JOQSA8LSBxdWFudGlsZShyb3dWYXJzKHdwbl92c2RfQXB1bF9zUk5BLCB1c2VOYW1lcz1UUlVFKSwgLjc1KSAgIyA3NXRoIHF1YW50aWxlIHZhcmlhYmlsaXR5CkFwdWxfY291bnRzX3NSTkFfdnNkX3E3NSA8LSB3cG5fdnNkX0FwdWxfc1JOQVsgcnZfd3BuX0FwdWxfc1JOQSA+IHE3NV93cG5fQXB1bF9zUk5BLCBdICU+JSBkYXRhLmZyYW1lICMgZmlsdGVyIHRvIHJldGFpbiBvbmx5IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzCndyaXRlLnRhYmxlKEFwdWxfY291bnRzX3NSTkFfdnNkX3E3NSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1BcHVsLXNSTkEtc3VtbWFyeS9BcHVsX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZF9xNzUudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQoKcTk1X3dwbl9BcHVsX3NSTkEgPC0gcXVhbnRpbGUocm93VmFycyh3cG5fdnNkX0FwdWxfc1JOQSwgdXNlTmFtZXM9VFJVRSksIC45NSkgICMgOTV0aCBxdWFudGlsZSB2YXJpYWJpbGl0eQpBcHVsX2NvdW50c19zUk5BX3ZzZF9xOTUgPC0gd3BuX3ZzZF9BcHVsX3NSTkFbIHJ2X3dwbl9BcHVsX3NSTkEgPiBxOTVfd3BuX0FwdWxfc1JOQSwgXSAlPiUgZGF0YS5mcmFtZSAjIGZpbHRlciB0byByZXRhaW4gb25seSB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcwp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zUk5BX3ZzZF9xOTUsIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtQXB1bC1zUk5BLXN1bW1hcnkvQXB1bF9jb3VudHNfc1JOQV92YXJpYW5jZXN0YWJpbGl6ZWRfcTk1LnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKYGBgCgojIyBQbG90IG5vcm1hbGl6ZWQgZGF0YQoKYGBge3IgcGxvdC1ub3JtYWxpemVkLXNSTkF9CkFwdWxfY291bnRzX3NSTkFfbm9ybV9sb25nIDwtIEFwdWxfY291bnRzX3NSTkFfbm9ybSAlPiUKICBtdXRhdGUoCiAgICBHZW5lX2lkID0gcm93Lm5hbWVzKEFwdWxfY291bnRzX3NSTkFfbm9ybSkKICApICU+JQogIHBpdm90X2xvbmdlcigtR2VuZV9pZCkKCkFwdWxfY291bnRzX3NSTkFfbm9ybV9sb25nICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG5hbWUsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoIGFuZ2xlID0gOTApCiAgKSArCiAgeWxpbSgwLCBOQSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJOb3JtYWxpemVkIEV4cHJlc3Npb24iLAogICAgeCA9ICJTYW1wbGUiLAogICAgeSA9ICJOb3JtYWxpemVkIGNvdW50cyIKICApCmBgYAoKCiMjIFBsb3QgdmFyaWFuY2Ugc3RhYmlsaXplZCBkYXRhCgpgYGB7ciBwbG90LXZzZC1zUk5BfQpBcHVsX2NvdW50c19zUk5BX3ZzZF9sb25nIDwtIEFwdWxfY291bnRzX3NSTkFfdnNkICU+JQogIG11dGF0ZSgKICAgIEdlbmVfaWQgPSByb3cubmFtZXMoQXB1bF9jb3VudHNfc1JOQV92c2QpCiAgKSAlPiUKICBwaXZvdF9sb25nZXIoLUdlbmVfaWQpCgpBcHVsX2NvdW50c19zUk5BX3ZzZF9sb25nICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG5hbWUsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoIGFuZ2xlID0gOTApCiAgKSArCiAgeWxpbSgwLCBOQSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWYXJpYW5jZSBTdGFiaWxpemVkIEV4cHJlc3Npb24iLAogICAgeCA9ICJTYW1wbGUiLAogICAgeSA9ICJWYXJpYW5jZSBzdGFiaWxpemVkIGRhdGEiCiAgKQpgYGAKCiMjIE5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscyBpbiBlYWNoIHNhbXBsZQoKYGBge3Igbm9ybS1leHByZXNzaW9uLWxldmVsLWhpc3RvZ3JhbXN9CiMgTWVsdCB0aGUgY291bnQgbWF0cml4IGludG8gbG9uZyBmb3JtYXQKQXB1bF9jb3VudHNfbm9ybV9tZWx0ZWQgPC0gbWVsdChBcHVsX2NvdW50c19zUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIG5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfbm9ybSA8LSBjb2xTdW1zKEFwdWxfY291bnRzX3NSTkFfbm9ybSkKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKdG90YWxfdHJhbnNjcmlwdHNfbm9ybV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHRvdGFsX3RyYW5zY3JpcHRzX25vcm0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFscyA9IHRvdGFsX3RyYW5zY3JpcHRzX25vcm0pCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KHRvdGFsX3RyYW5zY3JpcHRzX25vcm1fZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgVHJhbnNjcmlwdHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCgojIyBQQ0Egb2YgdmFyaWFuY2Ugc3RhYmlsaXplZCBkYXRhCgpgYGB7ciBQQ0F9CnBsb3RQQ0EodnNkX0FwdWxfc1JOQSwgaW50Z3JvdXA9IlNhbXBsZSIpCmBgYAoKIyMgU2FtcGxlIGNsdXN0ZXJpbmcKCmBgYHtyIHNhbXBsZS1jbHVzdGVyaW5nfQpzYW1wbGVfZGlzdHMgPC0gZGlzdCh0KGFzc2F5KHZzZF9BcHVsX3NSTkEpKSkKcGhlYXRtYXAoYXMubWF0cml4KHNhbXBsZV9kaXN0cyksIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJldWNsaWRlYW4iLCAKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImV1Y2xpZGVhbiIsIG1haW49IlNhbXBsZSBDbHVzdGVyaW5nIikKYGBgCgojIyBIZWF0bWFwcwoKT2YgbW9zdCB2YXJpYWJsZSB2YXJpYW5jZSBzdGFiaWxpemVkIHNSTkEgdHJhbnNjcmlwdHMKCmBgYHtyIGhlYXRtcGFzfQojIDc1dGggcXVhbnRpbGUKaGVhdF9jb2xvcnMgPC0gcmV2KGJyZXdlci5wYWwoMTIsICJSZFlsQnUiKSkKcGhlYXRtYXAoQXB1bF9jb3VudHNfc1JOQV92c2RfcTc1LCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLAogICAgICAgICBzY2FsZT0icm93IikKCiMgOTV0aCBxdWFudGlsZQpwaGVhdG1hcChBcHVsX2NvdW50c19zUk5BX3ZzZF9xOTUsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsCiAgICAgICAgIHNjYWxlPSJyb3ciKQpgYGAKCiMgTm9ybWFsaXplZCBtaVJOQSBjb3VudHMKCiMjIElzb2xhdGUgbm9ybWFsaXplZC92c2QgbWlSTkEKYGBge3IgbWlSTkEtbm9ybWFsaXplZC1taVJOQX0KQXB1bF9jb3VudHNfc1JOQV9ub3JtJE5hbWUgPC0gcm93bmFtZXMoQXB1bF9jb3VudHNfc1JOQV9ub3JtKQpBcHVsX2NvdW50c19taVJOQV9ub3JtIDwtIGxlZnRfam9pbihBcHVsX21ldGFkYXRhX21pUk5BLCBBcHVsX2NvdW50c19zUk5BX25vcm0sIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJnaXZlbl9taVJOQV9uYW1lIikgJT4lCiAgc2VsZWN0KHN0YXJ0c193aXRoKCJzYW1wbGUiKSkKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfbWlSTkFfbm9ybSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1BcHVsLXNSTkEtc3VtbWFyeS9BcHVsX2NvdW50c19taVJOQV9ub3JtYWxpemVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKCkFwdWxfY291bnRzX3NSTkFfdnNkJE5hbWUgPC0gcm93bmFtZXMoQXB1bF9jb3VudHNfc1JOQV92c2QpCkFwdWxfY291bnRzX21pUk5BX3ZzZCA8LSBsZWZ0X2pvaW4oQXB1bF9tZXRhZGF0YV9taVJOQSwgQXB1bF9jb3VudHNfc1JOQV92c2QsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJnaXZlbl9taVJOQV9uYW1lIikgJT4lCiAgc2VsZWN0KHN0YXJ0c193aXRoKCJzYW1wbGUiKSkKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfbWlSTkFfdnNkLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLUFwdWwtc1JOQS1zdW1tYXJ5L0FwdWxfY291bnRzX21pUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgTm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBtaVJOQS1ub3JtLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCA8LSBtZWx0KEFwdWxfY291bnRzX21pUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIG1pUk5BLW5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfbWlSTkFfbm9ybSA8LSBjb2xTdW1zKEFwdWxfY291bnRzX21pUk5BX25vcm0pCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX21pUk5BX25vcm1fZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtX2RmLCBhZXMoeCA9IHNhbXBsZSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgbWlSTkEgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIFRyYW5zY3JpcHRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKIyMgSGVhdG1hcAoKT2YgYWxsIG1pUk5BcwoKYGBge3IgbWlSTkEtaGVhdG1wYXN9CmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCnBoZWF0bWFwKEFwdWxfY291bnRzX21pUk5BX3ZzZCwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywKICAgICAgICAgc2NhbGU9InJvdyIpCgpgYGAK