Gene expression summary for Pocillopora tuahiniensis sRNA-seq data.

  • trimmed reads generated in deep-dive project

  • Reads aligned to Pocillopora meandrina transcriptome, details here

0.0.1 Install and load packages

library(tidyverse)
library(ggplot2)
library(reshape2)
library(pheatmap)
library(RColorBrewer)
library(DESeq2)

1 sRNA

1.1 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
Ptuh_counts_sRNA_data_OG <- read_delim("../output/05-Ptuh-sRNA-ShortStack_4.1.0/ShortStack_out/Counts.txt", delim="\t") 
head(Ptuh_counts_sRNA_data_OG)
# A tibble: 6 × 8
  Coords               Name  MIRNA sRNA-POC-47-S1-TP2-f…¹ sRNA-POC-48-S1-TP2-f…²
  <chr>                <chr> <chr>                  <dbl>                  <dbl>
1 Pocillopora_meandri… Clus… N                       1606                   1328
2 Pocillopora_meandri… Clus… N                         24                     51
3 Pocillopora_meandri… Clus… N                        244                    525
4 Pocillopora_meandri… Clus… N                        166                    167
5 Pocillopora_meandri… Clus… N                          6                     15
6 Pocillopora_meandri… Clus… N                         35                     37
# ℹ abbreviated names:
#   ¹​`sRNA-POC-47-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed`,
#   ²​`sRNA-POC-48-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed`
# ℹ 3 more variables:
#   `sRNA-POC-50-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
#   `sRNA-POC-53-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
#   `sRNA-POC-57-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed` <dbl>

1.2 Count data munging

Ptuh_counts_sRNA <- Ptuh_counts_sRNA_data_OG

# Remove excess portions of sample column names to just "sample###"
colnames(Ptuh_counts_sRNA) <- sub("-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed", "", colnames(Ptuh_counts_sRNA))
colnames(Ptuh_counts_sRNA) <- sub("sRNA-POC-", "sample", colnames(Ptuh_counts_sRNA))

# Keep just the counts and cluster names
Ptuh_counts_sRNA <- Ptuh_counts_sRNA %>% select("sample47", "sample48", "sample50", "sample53", "sample57", "Name")

# I'm not going to be doing any removal of low-count sRNAs for now

# Make the cluster names our new row names
Ptuh_counts_sRNA <- Ptuh_counts_sRNA %>% column_to_rownames(var = "Name")

write.table(Ptuh_counts_sRNA, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_sRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)

head(Ptuh_counts_sRNA)
          sample47 sample48 sample50 sample53 sample57
Cluster_1     1606     1328     1544     3021     3331
Cluster_2       24       51       67       52       91
Cluster_3      244      525      433      397      949
Cluster_4      166      167      273      318      333
Cluster_5        6       15       26       65       73
Cluster_6       35       37       33       58      123

1.3 Expression levels

Plot histograms of the expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_sRNA_melted <- melt(Ptuh_counts_sRNA, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_sRNA_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", 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()

1.4 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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) + 
  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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = uniques), vjust = -0.3, size = 3.5) + 
  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

2 miRNA

2.1 Load miRNA metadata

The ShortStack output Results.txt includes all clusters of sRNA reads, including those not annotated as valid miRNAs. Now that we’ve looked at all the sRNAs a bit, let’s focus in on those classified as miRNAs.

## This code needs miRNA names first ##
# # Join with full metadata sheet, which only contains valid miRNAs
# Ptuh_metadata_miRNA <- read_csv("../../../deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/Ptuh_results_mature_named.csv") 
# 
# Ptuh_counts_sRNA <- rownames_to_column(Ptuh_counts_sRNA, var = "Name")
# 
# Ptuh_counts_miRNA <- left_join(Ptuh_metadata_miRNA, Ptuh_counts_sRNA, by = c("Name" = "Name"))
# 
# # Keep just the counts and given miRNA names (e.g., based on match to previously described miRNA)
# Ptuh_counts_miRNA <- Ptuh_counts_miRNA %>% select("sample47", "sample48", "sample50", "sample53", "sample57", "given_miRNA_name")
# 
# # Make the miRNA names our new row names
# Ptuh_counts_miRNA <- Ptuh_counts_miRNA %>% column_to_rownames(var = "given_miRNA_name")
# 
# head(Ptuh_counts_miRNA)

## This code can be used until we have miRNA names ##
Ptuh_counts_miRNA <- Ptuh_counts_sRNA_data_OG

# Remove excess portions of sample column names to just "sample###"
colnames(Ptuh_counts_miRNA) <- sub("-S1-TP2-fastp-adapters-polyG-31bp-merged_condensed", "", colnames(Ptuh_counts_miRNA))
colnames(Ptuh_counts_miRNA) <- sub("sRNA-POC-", "sample", colnames(Ptuh_counts_miRNA))

# Keep only the sRNAs ID'd as valid miRNAs
Ptuh_counts_miRNA <- Ptuh_counts_miRNA %>% filter(MIRNA == "Y")

# Keep just the counts and cluster names
Ptuh_counts_miRNA <- Ptuh_counts_miRNA %>% select("sample47", "sample48", "sample50", "sample53", "sample57", "Name")

# Make the cluster names our new row names
Ptuh_counts_miRNA <- Ptuh_counts_miRNA %>% column_to_rownames(var = "Name")

write.table(Ptuh_counts_miRNA, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_miRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)

head(Ptuh_counts_miRNA)
            sample47 sample48 sample50 sample53 sample57
Cluster_21      4846     2433     1968     1452     1397
Cluster_36        39       44       20       41       33
Cluster_360   142599   101636   141199    84760    52034
Cluster_390      741      614      748      876      353
Cluster_757     2201      960     1596      944      621
Cluster_925    27988    22742    20636    26150     8840

2.2 Expression levels

Plot histograms of the expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_miRNA_melted <- melt(Ptuh_counts_miRNA, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_miRNA_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", color = "black") +
  scale_x_log10() +  # Optional: Log-transform the x-axis for better visualization
  facet_wrap(~sample, scales = "free_y") +
  labs(title = "miRNA Expression Level Histogram for Each Sample",
       x = "Expression Level (Counts)",
       y = "Frequency") +
  theme_minimal()

2.3 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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) + 
  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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = uniques), vjust = -0.3, size = 3.5) + 
  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

2.4 Heatmap

pheatmap(Ptuh_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(Ptuh_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)

3 siRNA

ShortStack’s primary purpose is to identify miRNAs from sRNA-seq data, but it also automatically annotates siRNA loci! Since siRNA potentially play an important role in transposon silencing in invertebrates, we should generate count matrices for siRNAs as well.

We can see clusters annotated as siRNAs in the Results.gff3 output file of ShortStack (sRNA ID shown in the 3rd column)

Ptuh_Resultsgff <- read.table("../output/05-Ptuh-sRNA-ShortStack_4.1.0/ShortStack_out/Results.gff3")
# Separate last column info into multiple columns for filtering
Ptuh_Resultsgff <- Ptuh_Resultsgff %>%
  separate(V9, into = c("Name", "DicerCall", "MIRNA"), sep = ";") %>%
  mutate(Name = sub("ID=", "", Name),
         DicerCall = sub("DicerCall=", "", DicerCall),
         MIRNA = sub("MIRNA=", "", MIRNA))
head(Ptuh_Resultsgff)
                                      V1         V2                 V3     V4
1 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack Unknown_sRNA_locus   9092
2 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack Unknown_sRNA_locus  53578
3 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack Unknown_sRNA_locus 150243
4 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack      siRNA22_locus 173728
5 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack Unknown_sRNA_locus 187562
6 Pocillopora_meandrina_HIv1___Sc0000000 ShortStack Unknown_sRNA_locus 485730
      V5    V6 V7 V8      Name DicerCall MIRNA
1   9521 10830  +  . Cluster_1         N     N
2  53997   285  +  . Cluster_2         N     N
3 150718  2548  -  . Cluster_3         N     N
4 174150  1257  +  . Cluster_4        22     N
5 188076   185  .  . Cluster_5         N     N
6 486254   286  +  . Cluster_6         N     N
# keep just the sRNA category column (V3), and the cluster names (Name)
# filter to only keep clusters ID'd as siRNAs
Ptuh_siRNA_clusters <- Ptuh_Resultsgff %>%
  select(V3, Name) %>%
  filter(str_detect(V3, regex("siRNA")))
head(Ptuh_siRNA_clusters)
             V3        Name
1 siRNA22_locus   Cluster_4
2 siRNA24_locus  Cluster_72
3 siRNA24_locus Cluster_100
4 siRNA24_locus Cluster_167
5 siRNA22_locus Cluster_280
6 siRNA22_locus Cluster_311
# Now use this list of clusters ID'd as siRNAs to filter our sRNA count matrix
# keep only the sample counts and cluster names
Ptuh_counts_sRNA <- rownames_to_column(Ptuh_counts_sRNA, var = "Name")
Ptuh_counts_siRNA <- left_join(Ptuh_siRNA_clusters, Ptuh_counts_sRNA, by = c("Name" = "Name")) %>%
  select(-V3)

# convert the column of cluster names into the df row names
Ptuh_counts_sRNA <- Ptuh_counts_sRNA %>% column_to_rownames(var="Name")
Ptuh_counts_siRNA <- Ptuh_counts_siRNA %>% column_to_rownames(var="Name")

head(Ptuh_counts_siRNA)
            sample47 sample48 sample50 sample53 sample57
Cluster_4        166      167      273      318      333
Cluster_72        76       11       25        0        7
Cluster_100      432      151      173      168       97
Cluster_167        0      113        0        0        1
Cluster_280        2        2       35       26       18
Cluster_311     3523     4898     4821     2509     1428
write.table(Ptuh_counts_siRNA, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_siRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)

3.1 Expression levels

Plot histograms of the expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_siRNA_melted <- melt(Ptuh_counts_siRNA, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_siRNA_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", color = "black") +
  scale_x_log10() +  # Optional: Log-transform the x-axis for better visualization
  facet_wrap(~sample, scales = "free_y") +
  labs(title = "siRNA Expression Level Histogram for Each Sample",
       x = "Expression Level (Counts)",
       y = "Frequency") +
  theme_minimal()

3.2 siRNA counts

First let’s check the total number of siRNAs 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_siRNA <- colSums(Ptuh_counts_siRNA)

# Create a data frame for plotting
total_siRNA_df <- data.frame(sample = names(total_siRNA),
                                   totals = total_siRNA)

# Plot the total number of transcripts for each sample
ggplot(total_siRNA_df, aes(x = sample, y = totals)) +
  geom_bar(stat = "identity", fill = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) + 
  labs(title = "Total Number of siRNAs per Sample",
       x = "Sample",
       y = "Total siRNAs") +
  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 siRNAs 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_siRNA <- colSums(Ptuh_counts_siRNA > 0)

# Create a data frame for plotting
unique_siRNA_df <- data.frame(sample = names(unique_siRNA),
                                    uniques = unique_siRNA)

# Plot the total number of unique transcripts for each sample
ggplot(unique_siRNA_df, aes(x = sample, y = uniques)) +
  geom_bar(stat = "identity", fill = "#7A2048", color = "black") +
  geom_text(aes(label = uniques), vjust = -0.3, size = 3.5) + 
  labs(title = "Total Number of Unique Expressed siRNAs per Sample",
       x = "Sample",
       y = "Unique siRNA") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Rotate x-axis labels for readability

3.3 Heatmap

pheatmap(Ptuh_counts_siRNA,
         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)

pheatmap(Ptuh_counts_siRNA,
         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)

4 ………..

5 Normalized sRNA counts

5.1 Normalize counts with DESeq2

5.1.1 Plot unnormalized sRNA data

Ptuh_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")

5.1.2 Metadata

DESeq2 requires a metadata data frame as input. I don’t have sample metadata though so, since we’re just doing DESeq2 for normalization purposes (not analysis purposes), I’m just going to create a dummy sheet

Ptuh_sample_names <- Ptuh_counts_sRNA %>%
#  select(-Name) %>%
  colnames()

Ptuh_metadata_sRNA <- data.frame(Sample = Ptuh_sample_names,
                            Species = rep("P.tuahiniensis", 5))
rownames(Ptuh_metadata_sRNA) <- Ptuh_sample_names

head(Ptuh_metadata_sRNA)
           Sample        Species
sample47 sample47 P.tuahiniensis
sample48 sample48 P.tuahiniensis
sample50 sample50 P.tuahiniensis
sample53 sample53 P.tuahiniensis
sample57 sample57 P.tuahiniensis

5.1.3 DESeq object

# Calculate DESeq object
Ptuh_counts_sRNA_rowNames <- Ptuh_counts_sRNA 
#%>% column_to_rownames(var = "Name")

dds_Ptuh_sRNA <- DESeqDataSetFromMatrix(countData = Ptuh_counts_sRNA_rowNames,
                              colData = Ptuh_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_Ptuh_sRNA <- DESeq(dds_Ptuh_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)
Ptuh_counts_sRNA_norm <- counts(dds_Ptuh_sRNA, normalized=TRUE) %>% data.frame()

write.table(Ptuh_counts_sRNA_norm, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_sRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)


# variance stabilized data
vsd_Ptuh_sRNA <- varianceStabilizingTransformation(dds_Ptuh_sRNA, blind=TRUE)
wpn_vsd_Ptuh_sRNA <- getVarianceStabilizedData(dds_Ptuh_sRNA)
rv_wpn_Ptuh_sRNA <- rowVars(wpn_vsd_Ptuh_sRNA, useNames=TRUE)

Ptuh_counts_sRNA_vsd <- data.frame(wpn_vsd_Ptuh_sRNA)
write.table(Ptuh_counts_sRNA_vsd, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_sRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

q75_wpn_Ptuh_sRNA <- quantile(rowVars(wpn_vsd_Ptuh_sRNA, useNames=TRUE), .75)  # 75th quantile variability
Ptuh_counts_sRNA_vsd_q75 <- wpn_vsd_Ptuh_sRNA[ rv_wpn_Ptuh_sRNA > q75_wpn_Ptuh_sRNA, ] %>% data.frame # filter to retain only the most variable genes
write.table(Ptuh_counts_sRNA_vsd_q75, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_sRNA_variancestabilized_q75.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

q95_wpn_Ptuh_sRNA <- quantile(rowVars(wpn_vsd_Ptuh_sRNA, useNames=TRUE), .95)  # 95th quantile variability
Ptuh_counts_sRNA_vsd_q95 <- wpn_vsd_Ptuh_sRNA[ rv_wpn_Ptuh_sRNA > q95_wpn_Ptuh_sRNA, ] %>% data.frame # filter to retain only the most variable genes
write.table(Ptuh_counts_sRNA_vsd_q95, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_sRNA_variancestabilized_q95.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

5.2 Plot normalized data

Ptuh_counts_sRNA_norm_long <- Ptuh_counts_sRNA_norm %>%
  mutate(
    Gene_id = row.names(Ptuh_counts_sRNA_norm)
  ) %>%
  pivot_longer(-Gene_id)

Ptuh_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"
  )

5.3 Plot variance stabilized data

Ptuh_counts_sRNA_vsd_long <- Ptuh_counts_sRNA_vsd %>%
  mutate(
    Gene_id = row.names(Ptuh_counts_sRNA_vsd)
  ) %>%
  pivot_longer(-Gene_id)

Ptuh_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"
  )

5.4 Normalized expression levels

Plot histograms of the normalized expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_norm_melted <- melt(Ptuh_counts_sRNA_norm, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_norm_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", 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()

5.5 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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) +
  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

5.6 PCA of variance stabilized data

plotPCA(vsd_Ptuh_sRNA, intgroup="Sample")

5.7 Sample clustering

sample_dists <- dist(t(assay(vsd_Ptuh_sRNA)))
pheatmap(as.matrix(sample_dists), clustering_distance_rows = "euclidean", 
         clustering_distance_cols = "euclidean", main="Sample Clustering")

5.8 Heatmaps

Of most variable variance stabilized sRNA transcripts

# 75th quantile
heat_colors <- rev(brewer.pal(12, "RdYlBu"))
pheatmap(Ptuh_counts_sRNA_vsd_q75, 
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

# 95th quantile
pheatmap(Ptuh_counts_sRNA_vsd_q95, 
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

6 Normalized miRNA counts

6.1 Isolate normalized/vsd miRNA

## Also written to use given miRNA names ##
# Ptuh_counts_sRNA_norm$Name <- rownames(Ptuh_counts_sRNA_norm)
# Ptuh_counts_miRNA_norm <- left_join(Ptuh_metadata_miRNA, Ptuh_counts_sRNA_norm, by = c("Name" = "Name")) %>%
#   column_to_rownames(var="given_miRNA_name") %>%
#   select(starts_with("sample"))
# write.table(Ptuh_counts_miRNA_norm, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_miRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)
# 
# Ptuh_counts_sRNA_vsd$Name <- rownames(Ptuh_counts_sRNA_vsd)
# Ptuh_counts_miRNA_vsd <- left_join(Ptuh_metadata_miRNA, Ptuh_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
#   column_to_rownames(var="given_miRNA_name") %>%
#   select(starts_with("sample"))
# write.table(Ptuh_counts_miRNA_vsd, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_miRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

## Use below until you have miRNA names ##
Ptuh_counts_sRNA_norm$Name <- rownames(Ptuh_counts_sRNA_norm)
Ptuh_counts_sRNA_vsd$Name <- rownames(Ptuh_counts_sRNA_vsd)

Ptuh_counts_miRNA_namesdf <- data.frame(Name = rownames(Ptuh_counts_miRNA)) 

Ptuh_counts_miRNA_norm <- left_join(Ptuh_counts_miRNA_namesdf, Ptuh_counts_sRNA_norm, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Ptuh_counts_miRNA_norm, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_miRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

Ptuh_counts_miRNA_vsd <- left_join(Ptuh_counts_miRNA_namesdf, Ptuh_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Ptuh_counts_miRNA_vsd, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_miRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

6.2 Normalized expression levels

Plot histograms of the normalized expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_miRNA_norm_melted <- melt(Ptuh_counts_miRNA_norm, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_miRNA_norm_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", 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()

6.3 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(Ptuh_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 = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) +
  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

6.4 Heatmap

Of all miRNAs

heat_colors <- rev(brewer.pal(12, "RdYlBu"))
pheatmap(as.matrix(Ptuh_counts_miRNA_vsd[apply(Ptuh_counts_miRNA_vsd, 1, var) > 0, ]), 
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

7 Normalized siRNA counts

7.1 Isolate normalized/vsd siRNA

Ptuh_counts_sRNA_norm$Name <- rownames(Ptuh_counts_sRNA_norm)
Ptuh_counts_sRNA_vsd$Name <- rownames(Ptuh_counts_sRNA_vsd)

Ptuh_counts_siRNA_namesdf <- data.frame(Name = rownames(Ptuh_counts_siRNA)) 

Ptuh_counts_siRNA_norm <- left_join(Ptuh_counts_siRNA_namesdf, Ptuh_counts_sRNA_norm, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Ptuh_counts_siRNA_norm, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_siRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

Ptuh_counts_siRNA_vsd <- left_join(Ptuh_counts_siRNA_namesdf, Ptuh_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Ptuh_counts_siRNA_vsd, file = "../output/03.1-Ptuh-sRNA-summary/Ptuh_counts_siRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

7.2 Normalized expression levels

Plot histograms of the normalized expression levels in each sample

# Melt the count matrix into long format
Ptuh_counts_siRNA_norm_melted <- melt(Ptuh_counts_siRNA_norm, variable.name = "sample", value.name = "counts")

# Plot the expression level histograms for each sample
ggplot(Ptuh_counts_siRNA_norm_melted, aes(x = counts)) +
  geom_histogram(binwidth = 1, fill = "#7A2048", 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()

7.3 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_siRNA_norm <- colSums(Ptuh_counts_siRNA_norm)

# Create a data frame for plotting
total_transcripts_siRNA_norm_df <- data.frame(sample = names(total_transcripts_siRNA_norm),
                                   totals = total_transcripts_siRNA_norm)

# Plot the total number of transcripts for each sample
ggplot(total_transcripts_siRNA_norm_df, aes(x = sample, y = totals)) +
  geom_bar(stat = "identity", fill = "#7A2048", color = "black") +
  geom_text(aes(label = totals), vjust = -0.3, size = 3.5) +
  labs(title = "Total Number of siRNA 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

7.4 Heatmap

Of all siRNAs

heat_colors <- rev(brewer.pal(12, "RdYlBu"))
pheatmap(as.matrix(Ptuh_counts_siRNA_vsd[apply(Ptuh_counts_siRNA_vsd, 1, var) > 0, ]), 
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

LS0tCnRpdGxlOiAiMDMuMS1QdHVoLXNSTkEtc3VtbWFyeSIKYXV0aG9yOiAiS2F0aGxlZW4gRHVya2luIgpkYXRlOiAiMjAyNC0wOS0wNiIKYWx3YXlzX2FsbG93X2h0bWw6IHRydWUKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGh0bWxfcHJldmlldzogdHJ1ZSAKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBUUlVFLCAgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKR2VuZSBleHByZXNzaW9uIHN1bW1hcnkgZm9yICpQb2NpbGxvcG9yYSB0dWFoaW5pZW5zaXMqIHNSTkEtc2VxIGRhdGEuCgotICAgdHJpbW1lZCByZWFkcyBnZW5lcmF0ZWQgaW4gYGRlZXAtZGl2ZWAgcHJvamVjdAoKLSAgIFJlYWRzIGFsaWduZWQgdG8gKlBvY2lsbG9wb3JhIG1lYW5kcmluYSogdHJhbnNjcmlwdG9tZSwgZGV0YWlscyBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL3Vyb2wtZTUvZGVlcC1kaXZlL2Jsb2IvbWFpbi9GLVB0dWgvY29kZS8xMi1QdHVoLVJOQXNlcS1rYWxsaXN0by5tZCkKCgojIyMgSW5zdGFsbCBhbmQgbG9hZCBwYWNrYWdlcwoKYGBge3IgbG9hZF9saWJyYXJpZXMsIGlubGN1ZGUgPSBUUlVFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShERVNlcTIpCmBgYAoKCiMgc1JOQQoKIyMgTG9hZCBjb3VudCBkYXRhCgpMb2FkIGluIHRoZSBzUk5BIGNvdW50IG1hdHJpeCBnZW5lcmF0ZWQgdXNpbmcgU2hvcnRTdGFjayA0LjEuMC4gS2VlcCBpbiBtaW5kIHRoaXMgZGF0YSBpbmNsdWRlcyBjb3VudHMgb2YgYWxsIHNSTkFzLCBub3QganVzdCBtaVJOQXMuIAoKYGBge3IgbG9hZC1zUk5BLWNvdW50c30KIyBSZWFkIGluIHNSTkEgY291bnRzIGRhdGEKUHR1aF9jb3VudHNfc1JOQV9kYXRhX09HIDwtIHJlYWRfZGVsaW0oIi4uL291dHB1dC8wNS1QdHVoLXNSTkEtU2hvcnRTdGFja180LjEuMC9TaG9ydFN0YWNrX291dC9Db3VudHMudHh0IiwgZGVsaW09Ilx0IikgCmhlYWQoUHR1aF9jb3VudHNfc1JOQV9kYXRhX09HKQpgYGAKCiMjIENvdW50IGRhdGEgbXVuZ2luZwoKYGBge3Igc1JOQS1jb3VudC1kYXRhLW11bmdpbmd9ClB0dWhfY291bnRzX3NSTkEgPC0gUHR1aF9jb3VudHNfc1JOQV9kYXRhX09HCgojIFJlbW92ZSBleGNlc3MgcG9ydGlvbnMgb2Ygc2FtcGxlIGNvbHVtbiBuYW1lcyB0byBqdXN0ICJzYW1wbGUjIyMiCmNvbG5hbWVzKFB0dWhfY291bnRzX3NSTkEpIDwtIHN1YigiLVMxLVRQMi1mYXN0cC1hZGFwdGVycy1wb2x5Ry0zMWJwLW1lcmdlZF9jb25kZW5zZWQiLCAiIiwgY29sbmFtZXMoUHR1aF9jb3VudHNfc1JOQSkpCmNvbG5hbWVzKFB0dWhfY291bnRzX3NSTkEpIDwtIHN1Yigic1JOQS1QT0MtIiwgInNhbXBsZSIsIGNvbG5hbWVzKFB0dWhfY291bnRzX3NSTkEpKQoKIyBLZWVwIGp1c3QgdGhlIGNvdW50cyBhbmQgY2x1c3RlciBuYW1lcwpQdHVoX2NvdW50c19zUk5BIDwtIFB0dWhfY291bnRzX3NSTkEgJT4lIHNlbGVjdCgic2FtcGxlNDciLCAic2FtcGxlNDgiLCAic2FtcGxlNTAiLCAic2FtcGxlNTMiLCAic2FtcGxlNTciLCAiTmFtZSIpCgojIEknbSBub3QgZ29pbmcgdG8gYmUgZG9pbmcgYW55IHJlbW92YWwgb2YgbG93LWNvdW50IHNSTkFzIGZvciBub3cKCiMgTWFrZSB0aGUgY2x1c3RlciBuYW1lcyBvdXIgbmV3IHJvdyBuYW1lcwpQdHVoX2NvdW50c19zUk5BIDwtIFB0dWhfY291bnRzX3NSTkEgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiTmFtZSIpCgp3cml0ZS50YWJsZShQdHVoX2NvdW50c19zUk5BLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLVB0dWgtc1JOQS1zdW1tYXJ5L1B0dWhfc1JOQV9TaG9ydFN0YWNrX2NvdW50c19mb3JtYXR0ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSwgcXVvdGUgPSBGQUxTRSkKCmhlYWQoUHR1aF9jb3VudHNfc1JOQSkKYGBgCgoKIyMgRXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgaW4gZWFjaCBzYW1wbGUKCmBgYHtyIGV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApQdHVoX2NvdW50c19zUk5BX21lbHRlZCA8LSBtZWx0KFB0dWhfY291bnRzX3NSTkEsIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChQdHVoX2NvdW50c19zUk5BX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBUcmFuc2NyaXB0IGNvdW50cwoKRmlyc3QgbGV0J3MgY2hlY2sgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBpbiBlYWNoIHNhbXBsZSAtLSBrZWVwIGluIG1pbmQgdGhpcyBleHByZXNzaW9uIGRhdGEgaGFzICpub3QqIGJlZW4gbm9ybWFsaXplZCB5ZXQsIHNvIHRoZXJlIG1heSBiZSBkaWZmZXJlbnQgdG90YWxzIGZvciBlYWNoIHNhbXBsZQpgYGB7ciB0cmFuc2NyaXB0LWNvdW50cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQp0b3RhbF90cmFuc2NyaXB0cyA8LSBjb2xTdW1zKFB0dWhfY291bnRzX3NSTkEpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModG90YWxfdHJhbnNjcmlwdHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFscyA9IHRvdGFsX3RyYW5zY3JpcHRzKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19kZiwgYWVzKHggPSBzYW1wbGUsIHkgPSB0b3RhbHMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzdBMjA0OCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB0b3RhbHMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsgCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIFRyYW5zY3JpcHRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKTm93IGxldCdzIGNoZWNrIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIHRoYXQgaXMsIGhvdyBtYW55IHVuaXF1ZSBzUk5BcyBhcmUgZXhwcmVzc2VkIGluIGVhY2ggc2FtcGxlPyBUaGlzIHNob3VsZCBiZSBwcmV0dHkgbXVjaCB0aGUgc2FtZSBhY3Jvc3Mgc2FtcGxlcywgZXZlbiB3aXRob3V0IG5vcm1hbGl6YXRpb24uCgpgYGB7ciB0b3RhbC11bmlxdWUtdHJhbnNjcmlwdHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgKG5vbi16ZXJvIGNvdW50cykgZm9yIGVhY2ggc2FtcGxlCnVuaXF1ZV90cmFuc2NyaXB0cyA8LSBjb2xTdW1zKFB0dWhfY291bnRzX3NSTkEgPiAwKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp1bmlxdWVfdHJhbnNjcmlwdHNfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh1bmlxdWVfdHJhbnNjcmlwdHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWVzID0gdW5pcXVlX3RyYW5zY3JpcHRzKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodW5pcXVlX3RyYW5zY3JpcHRzX2RmLCBhZXMoeCA9IHNhbXBsZSwgeSA9IHVuaXF1ZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzdBMjA0OCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB1bmlxdWVzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArIAogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIFVuaXF1ZSBFeHByZXNzZWQgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBUcmFuc2NyaXB0cyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKICAgCgojIG1pUk5BCgojIyBMb2FkIG1pUk5BIG1ldGFkYXRhCgpUaGUgU2hvcnRTdGFjayBvdXRwdXQgUmVzdWx0cy50eHQgaW5jbHVkZXMgYWxsIGNsdXN0ZXJzIG9mIHNSTkEgcmVhZHMsIGluY2x1ZGluZyB0aG9zZSBub3QgYW5ub3RhdGVkIGFzIHZhbGlkIG1pUk5Bcy4gTm93IHRoYXQgd2UndmUgbG9va2VkIGF0IGFsbCB0aGUgc1JOQXMgYSBiaXQsIGxldCdzIGZvY3VzIGluIG9uIHRob3NlIGNsYXNzaWZpZWQgYXMgbWlSTkFzLgoKYGBge3IgbWlSTkEtY291bnQtZGF0YS1tdW5naW5nfQojIyBUaGlzIGNvZGUgbmVlZHMgbWlSTkEgbmFtZXMgZmlyc3QgIyMKIyAjIEpvaW4gd2l0aCBmdWxsIG1ldGFkYXRhIHNoZWV0LCB3aGljaCBvbmx5IGNvbnRhaW5zIHZhbGlkIG1pUk5BcwojIFB0dWhfbWV0YWRhdGFfbWlSTkEgPC0gcmVhZF9jc3YoIi4uLy4uLy4uL2RlZXAtZGl2ZS9ERUYtY3Jvc3Mtc3BlY2llcy9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL1B0dWhfcmVzdWx0c19tYXR1cmVfbmFtZWQuY3N2IikgCiMgCiMgUHR1aF9jb3VudHNfc1JOQSA8LSByb3duYW1lc190b19jb2x1bW4oUHR1aF9jb3VudHNfc1JOQSwgdmFyID0gIk5hbWUiKQojIAojIFB0dWhfY291bnRzX21pUk5BIDwtIGxlZnRfam9pbihQdHVoX21ldGFkYXRhX21pUk5BLCBQdHVoX2NvdW50c19zUk5BLCBieSA9IGMoIk5hbWUiID0gIk5hbWUiKSkKIyAKIyAjIEtlZXAganVzdCB0aGUgY291bnRzIGFuZCBnaXZlbiBtaVJOQSBuYW1lcyAoZS5nLiwgYmFzZWQgb24gbWF0Y2ggdG8gcHJldmlvdXNseSBkZXNjcmliZWQgbWlSTkEpCiMgUHR1aF9jb3VudHNfbWlSTkEgPC0gUHR1aF9jb3VudHNfbWlSTkEgJT4lIHNlbGVjdCgic2FtcGxlNDciLCAic2FtcGxlNDgiLCAic2FtcGxlNTAiLCAic2FtcGxlNTMiLCAic2FtcGxlNTciLCAiZ2l2ZW5fbWlSTkFfbmFtZSIpCiMgCiMgIyBNYWtlIHRoZSBtaVJOQSBuYW1lcyBvdXIgbmV3IHJvdyBuYW1lcwojIFB0dWhfY291bnRzX21pUk5BIDwtIFB0dWhfY291bnRzX21pUk5BICU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gImdpdmVuX21pUk5BX25hbWUiKQojIAojIGhlYWQoUHR1aF9jb3VudHNfbWlSTkEpCgojIyBUaGlzIGNvZGUgY2FuIGJlIHVzZWQgdW50aWwgd2UgaGF2ZSBtaVJOQSBuYW1lcyAjIwpQdHVoX2NvdW50c19taVJOQSA8LSBQdHVoX2NvdW50c19zUk5BX2RhdGFfT0cKCiMgUmVtb3ZlIGV4Y2VzcyBwb3J0aW9ucyBvZiBzYW1wbGUgY29sdW1uIG5hbWVzIHRvIGp1c3QgInNhbXBsZSMjIyIKY29sbmFtZXMoUHR1aF9jb3VudHNfbWlSTkEpIDwtIHN1YigiLVMxLVRQMi1mYXN0cC1hZGFwdGVycy1wb2x5Ry0zMWJwLW1lcmdlZF9jb25kZW5zZWQiLCAiIiwgY29sbmFtZXMoUHR1aF9jb3VudHNfbWlSTkEpKQpjb2xuYW1lcyhQdHVoX2NvdW50c19taVJOQSkgPC0gc3ViKCJzUk5BLVBPQy0iLCAic2FtcGxlIiwgY29sbmFtZXMoUHR1aF9jb3VudHNfbWlSTkEpKQoKIyBLZWVwIG9ubHkgdGhlIHNSTkFzIElEJ2QgYXMgdmFsaWQgbWlSTkFzClB0dWhfY291bnRzX21pUk5BIDwtIFB0dWhfY291bnRzX21pUk5BICU+JSBmaWx0ZXIoTUlSTkEgPT0gIlkiKQoKIyBLZWVwIGp1c3QgdGhlIGNvdW50cyBhbmQgY2x1c3RlciBuYW1lcwpQdHVoX2NvdW50c19taVJOQSA8LSBQdHVoX2NvdW50c19taVJOQSAlPiUgc2VsZWN0KCJzYW1wbGU0NyIsICJzYW1wbGU0OCIsICJzYW1wbGU1MCIsICJzYW1wbGU1MyIsICJzYW1wbGU1NyIsICJOYW1lIikKCiMgTWFrZSB0aGUgY2x1c3RlciBuYW1lcyBvdXIgbmV3IHJvdyBuYW1lcwpQdHVoX2NvdW50c19taVJOQSA8LSBQdHVoX2NvdW50c19taVJOQSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJOYW1lIikKCndyaXRlLnRhYmxlKFB0dWhfY291bnRzX21pUk5BLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLVB0dWgtc1JOQS1zdW1tYXJ5L1B0dWhfbWlSTkFfU2hvcnRTdGFja19jb3VudHNfZm9ybWF0dGVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCgpoZWFkKFB0dWhfY291bnRzX21pUk5BKQoKYGBgCgojIyBFeHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBleHByZXNzaW9uIGxldmVscyBpbiBlYWNoIHNhbXBsZQoKYGBge3IgbWlSTkEtZXhwcmVzc2lvbi1sZXZlbC1oaXN0b2dyYW1zfQojIE1lbHQgdGhlIGNvdW50IG1hdHJpeCBpbnRvIGxvbmcgZm9ybWF0ClB0dWhfY291bnRzX21pUk5BX21lbHRlZCA8LSBtZWx0KFB0dWhfY291bnRzX21pUk5BLCB2YXJpYWJsZS5uYW1lID0gInNhbXBsZSIsIHZhbHVlLm5hbWUgPSAiY291bnRzIikKCiMgUGxvdCB0aGUgZXhwcmVzc2lvbiBsZXZlbCBoaXN0b2dyYW1zIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QoUHR1aF9jb3VudHNfbWlSTkFfbWVsdGVkLCBhZXMoeCA9IGNvdW50cykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiIzdBMjA0OCIsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfbG9nMTAoKSArICAjIE9wdGlvbmFsOiBMb2ctdHJhbnNmb3JtIHRoZSB4LWF4aXMgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uCiAgZmFjZXRfd3JhcCh+c2FtcGxlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnModGl0bGUgPSAibWlSTkEgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBtaVJOQSBjb3VudHMKCkZpcnN0IGxldCdzIGNoZWNrIHRoZSB0b3RhbCBudW1iZXIgb2YgbWlSTkFzIGluIGVhY2ggc2FtcGxlIC0tIGtlZXAgaW4gbWluZCB0aGlzIGV4cHJlc3Npb24gZGF0YSBoYXMgKm5vdCogYmVlbiBub3JtYWxpemVkIHlldCwgc28gdGhlcmUgbWF5IGJlIGRpZmZlcmVudCB0b3RhbHMgZm9yIGVhY2ggc2FtcGxlCmBgYHtyIG1pUk5BLWNvdW50cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQp0b3RhbF9taVJOQSA8LSBjb2xTdW1zKFB0dWhfY291bnRzX21pUk5BKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp0b3RhbF9taVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHRvdGFsX21pUk5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF9taVJOQSkKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodG90YWxfbWlSTkFfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWxzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArIAogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIG1pUk5BcyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgbWlSTkFzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKTm93IGxldCdzIGNoZWNrIHRoZSBudW1iZXIgb2YgdW5pcXVlIG1pUk5BcyBpbiBlYWNoIHNhbXBsZSAtLSBUaGlzIHNob3VsZCBiZSBwcmV0dHkgbXVjaCB0aGUgc2FtZSBhY3Jvc3Mgc2FtcGxlcywgZXZlbiB3aXRob3V0IG5vcm1hbGl6YXRpb24uCgpgYGB7ciB0b3RhbC11bmlxdWUtbWlSTkEtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgKG5vbi16ZXJvIGNvdW50cykgZm9yIGVhY2ggc2FtcGxlCnVuaXF1ZV9taVJOQSA8LSBjb2xTdW1zKFB0dWhfY291bnRzX21pUk5BID4gMCkKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKdW5pcXVlX21pUk5BX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModW5pcXVlX21pUk5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcXVlcyA9IHVuaXF1ZV9taVJOQSkKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHVuaXF1ZSB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KHVuaXF1ZV9taVJOQV9kZiwgYWVzKHggPSBzYW1wbGUsIHkgPSB1bmlxdWVzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdW5pcXVlcyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKyAKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBVbmlxdWUgRXhwcmVzc2VkIG1pUk5BcyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVW5pcXVlIG1pUk5BIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKIyMgSGVhdG1hcAoKYGBge3IgbWlSTkEtaGVhdG1hcH0KcGhlYXRtYXAoUHR1aF9jb3VudHNfbWlSTkEsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDUwKSwKICAgICAgICAgZm9udHNpemVfcm93ID0gOCwKICAgICAgICAgZm9udHNpemVfY29sID0gOCkKYGBgCldlbGwuLi4gdGhlcmUncyBsaWtlIDIgbWlSTkFzIHdpdGggbXVjaCBoaWdoZXIgZXhwcmVzc2lvbiB0aGFuIHRoZSBvdGhlcnMsIHdoaWNoIGlzIG1ha2luZyB2aXN1YWxpemluZyByZWxhdGl2ZSBkaWZmZXJlbmNlcyBkaWZmaWN1bHQuIExldCdzIHJlZG8gdGhlIGhlYXRtYXAsIG5vcm1hbGl6aW5nIGVhY2ggcm93IHRvIHZpZXcgcmVsYXRpdmUgZGlmZmVyZW5jZSBpbiBleHByZXNzaW9uIGJldHdlZW4gc2FtcGxlcyAoYHNjYWxlPSdyb3cnYCkKCmBgYHtyIG1pUk5BLWhlYXRtYXAtcm93c2NhbGV9CnBoZWF0bWFwKFB0dWhfY291bnRzX21pUk5BLAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIHNjYWxlID0gJ3JvdycsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCksCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgIGZvbnRzaXplX2NvbCA9IDgpCmBgYAoKIyBzaVJOQQoKU2hvcnRTdGFjaydzIHByaW1hcnkgcHVycG9zZSBpcyB0byBpZGVudGlmeSBtaVJOQXMgZnJvbSBzUk5BLXNlcSBkYXRhLCBidXQgaXQgYWxzbyBhdXRvbWF0aWNhbGx5IGFubm90YXRlcyBzaVJOQSBsb2NpISBTaW5jZSBzaVJOQSBwb3RlbnRpYWxseSBwbGF5IGFuIGltcG9ydGFudCByb2xlIGluIHRyYW5zcG9zb24gc2lsZW5jaW5nIGluIGludmVydGVicmF0ZXMsIHdlIHNob3VsZCBnZW5lcmF0ZSBjb3VudCBtYXRyaWNlcyBmb3Igc2lSTkFzIGFzIHdlbGwuIAoKV2UgY2FuIHNlZSBjbHVzdGVycyBhbm5vdGF0ZWQgYXMgc2lSTkFzIGluIHRoZSBgUmVzdWx0cy5nZmYzYCBvdXRwdXQgZmlsZSBvZiBTaG9ydFN0YWNrIChzUk5BIElEIHNob3duIGluIHRoZSAzcmQgY29sdW1uKQoKYGBge3Igc2lSTkEtY291bnQtZGF0YS1tdW5naW5nfQpQdHVoX1Jlc3VsdHNnZmYgPC0gcmVhZC50YWJsZSgiLi4vb3V0cHV0LzA1LVB0dWgtc1JOQS1TaG9ydFN0YWNrXzQuMS4wL1Nob3J0U3RhY2tfb3V0L1Jlc3VsdHMuZ2ZmMyIpCiMgU2VwYXJhdGUgbGFzdCBjb2x1bW4gaW5mbyBpbnRvIG11bHRpcGxlIGNvbHVtbnMgZm9yIGZpbHRlcmluZwpQdHVoX1Jlc3VsdHNnZmYgPC0gUHR1aF9SZXN1bHRzZ2ZmICU+JQogIHNlcGFyYXRlKFY5LCBpbnRvID0gYygiTmFtZSIsICJEaWNlckNhbGwiLCAiTUlSTkEiKSwgc2VwID0gIjsiKSAlPiUKICBtdXRhdGUoTmFtZSA9IHN1YigiSUQ9IiwgIiIsIE5hbWUpLAogICAgICAgICBEaWNlckNhbGwgPSBzdWIoIkRpY2VyQ2FsbD0iLCAiIiwgRGljZXJDYWxsKSwKICAgICAgICAgTUlSTkEgPSBzdWIoIk1JUk5BPSIsICIiLCBNSVJOQSkpCmhlYWQoUHR1aF9SZXN1bHRzZ2ZmKQoKIyBrZWVwIGp1c3QgdGhlIHNSTkEgY2F0ZWdvcnkgY29sdW1uIChWMyksIGFuZCB0aGUgY2x1c3RlciBuYW1lcyAoTmFtZSkKIyBmaWx0ZXIgdG8gb25seSBrZWVwIGNsdXN0ZXJzIElEJ2QgYXMgc2lSTkFzClB0dWhfc2lSTkFfY2x1c3RlcnMgPC0gUHR1aF9SZXN1bHRzZ2ZmICU+JQogIHNlbGVjdChWMywgTmFtZSkgJT4lCiAgZmlsdGVyKHN0cl9kZXRlY3QoVjMsIHJlZ2V4KCJzaVJOQSIpKSkKaGVhZChQdHVoX3NpUk5BX2NsdXN0ZXJzKQoKIyBOb3cgdXNlIHRoaXMgbGlzdCBvZiBjbHVzdGVycyBJRCdkIGFzIHNpUk5BcyB0byBmaWx0ZXIgb3VyIHNSTkEgY291bnQgbWF0cml4CiMga2VlcCBvbmx5IHRoZSBzYW1wbGUgY291bnRzIGFuZCBjbHVzdGVyIG5hbWVzClB0dWhfY291bnRzX3NSTkEgPC0gcm93bmFtZXNfdG9fY29sdW1uKFB0dWhfY291bnRzX3NSTkEsIHZhciA9ICJOYW1lIikKUHR1aF9jb3VudHNfc2lSTkEgPC0gbGVmdF9qb2luKFB0dWhfc2lSTkFfY2x1c3RlcnMsIFB0dWhfY291bnRzX3NSTkEsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBzZWxlY3QoLVYzKQoKIyBjb252ZXJ0IHRoZSBjb2x1bW4gb2YgY2x1c3RlciBuYW1lcyBpbnRvIHRoZSBkZiByb3cgbmFtZXMKUHR1aF9jb3VudHNfc1JOQSA8LSBQdHVoX2NvdW50c19zUk5BICU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJOYW1lIikKUHR1aF9jb3VudHNfc2lSTkEgPC0gUHR1aF9jb3VudHNfc2lSTkEgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXI9Ik5hbWUiKQoKaGVhZChQdHVoX2NvdW50c19zaVJOQSkKCndyaXRlLnRhYmxlKFB0dWhfY291bnRzX3NpUk5BLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLVB0dWgtc1JOQS1zdW1tYXJ5L1B0dWhfc2lSTkFfU2hvcnRTdGFja19jb3VudHNfZm9ybWF0dGVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgRXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgaW4gZWFjaCBzYW1wbGUKCmBgYHtyIHNpUk5BLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApQdHVoX2NvdW50c19zaVJOQV9tZWx0ZWQgPC0gbWVsdChQdHVoX2NvdW50c19zaVJOQSwgdmFyaWFibGUubmFtZSA9ICJzYW1wbGUiLCB2YWx1ZS5uYW1lID0gImNvdW50cyIpCgojIFBsb3QgdGhlIGV4cHJlc3Npb24gbGV2ZWwgaGlzdG9ncmFtcyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KFB0dWhfY291bnRzX3NpUk5BX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gInNpUk5BIEV4cHJlc3Npb24gTGV2ZWwgSGlzdG9ncmFtIGZvciBFYWNoIFNhbXBsZSIsCiAgICAgICB4ID0gIkV4cHJlc3Npb24gTGV2ZWwgKENvdW50cykiLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgc2lSTkEgY291bnRzCgpGaXJzdCBsZXQncyBjaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHNpUk5BcyBpbiBlYWNoIHNhbXBsZSAtLSBrZWVwIGluIG1pbmQgdGhpcyBleHByZXNzaW9uIGRhdGEgaGFzICpub3QqIGJlZW4gbm9ybWFsaXplZCB5ZXQsIHNvIHRoZXJlIG1heSBiZSBkaWZmZXJlbnQgdG90YWxzIGZvciBlYWNoIHNhbXBsZQpgYGB7ciBzaVJOQS1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfc2lSTkEgPC0gY29sU3VtcyhQdHVoX2NvdW50c19zaVJOQSkKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKdG90YWxfc2lSTkFfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF9zaVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxzID0gdG90YWxfc2lSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KHRvdGFsX3NpUk5BX2RmLCBhZXMoeCA9IHNhbXBsZSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjN0EyMDQ4IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFscyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKyAKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBzaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIHNpUk5BcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCk5vdyBsZXQncyBjaGVjayB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBzaVJOQXMgaW4gZWFjaCBzYW1wbGUgLS0gVGhpcyBzaG91bGQgYmUgcHJldHR5IG11Y2ggdGhlIHNhbWUgYWNyb3NzIHNhbXBsZXMsIGV2ZW4gd2l0aG91dCBub3JtYWxpemF0aW9uLgoKYGBge3IgdG90YWwtdW5pcXVlLXNpUk5BLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIChub24temVybyBjb3VudHMpIGZvciBlYWNoIHNhbXBsZQp1bmlxdWVfc2lSTkEgPC0gY29sU3VtcyhQdHVoX2NvdW50c19zaVJOQSA+IDApCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnVuaXF1ZV9zaVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHVuaXF1ZV9zaVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZXMgPSB1bmlxdWVfc2lSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh1bmlxdWVfc2lSTkFfZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdW5pcXVlcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjN0EyMDQ4IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHVuaXF1ZXMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsgCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVW5pcXVlIEV4cHJlc3NlZCBzaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBzaVJOQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIEhlYXRtYXAKCmBgYHtyIHNpUk5BLWhlYXRtYXB9CnBoZWF0bWFwKFB0dWhfY291bnRzX3NpUk5BLAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCksCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgIGZvbnRzaXplX2NvbCA9IDgpCmBgYAoKYGBge3Igc2lSTkEtaGVhdG1hcC1yb3dzY2FsZX0KcGhlYXRtYXAoUHR1aF9jb3VudHNfc2lSTkEsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgc2NhbGUgPSAncm93JywKICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDUwKSwKICAgICAgICAgZm9udHNpemVfcm93ID0gOCwKICAgICAgICAgZm9udHNpemVfY29sID0gOCkKYGBgCgoKIyAuLi4uLi4uLi4uLgoKIyBOb3JtYWxpemVkIHNSTkEgY291bnRzCgojIyBOb3JtYWxpemUgY291bnRzIHdpdGggREVTZXEyCgojIyMgUGxvdCB1bm5vcm1hbGl6ZWQgc1JOQSBkYXRhCgpgYGB7ciBwbG90LXVubm9ybWFsaXplZC1zUk5BfQoKUHR1aF9jb3VudHNfc1JOQSAlPiUgCiMgIHNlbGVjdCgtTmFtZSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJzYW1wbGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSBzYW1wbGUsIHkgPSBjb3VudCkpICsKICBnZW9tX3Zpb2xpbigpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJVbm5vcm1hbGl6ZWQgc1JOQSBjb3VudHMiLAogICAgICAgeCA9ICJTYW1wbGUiLAogICAgICAgeSA9ICJjb3VudCIpCmBgYAoKIyMjIE1ldGFkYXRhCgpERVNlcTIgcmVxdWlyZXMgYSBtZXRhZGF0YSBkYXRhIGZyYW1lIGFzIGlucHV0LiBJIGRvbid0IGhhdmUgc2FtcGxlIG1ldGFkYXRhIHRob3VnaCBzbywgc2luY2Ugd2UncmUganVzdCBkb2luZyBERVNlcTIgZm9yIG5vcm1hbGl6YXRpb24gcHVycG9zZXMgKG5vdCBhbmFseXNpcyBwdXJwb3NlcyksIEknbSBqdXN0IGdvaW5nIHRvIGNyZWF0ZSBhIGR1bW15IHNoZWV0CgpgYGB7ciBtYWtlLXNSTkEtbWV0YWRhdGEtZGF0YWZyYW1lfQpQdHVoX3NhbXBsZV9uYW1lcyA8LSBQdHVoX2NvdW50c19zUk5BICU+JQojICBzZWxlY3QoLU5hbWUpICU+JQogIGNvbG5hbWVzKCkKClB0dWhfbWV0YWRhdGFfc1JOQSA8LSBkYXRhLmZyYW1lKFNhbXBsZSA9IFB0dWhfc2FtcGxlX25hbWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3BlY2llcyA9IHJlcCgiUC50dWFoaW5pZW5zaXMiLCA1KSkKcm93bmFtZXMoUHR1aF9tZXRhZGF0YV9zUk5BKSA8LSBQdHVoX3NhbXBsZV9uYW1lcwoKaGVhZChQdHVoX21ldGFkYXRhX3NSTkEpCmBgYAoKIyMjIERFU2VxIG9iamVjdAoKYGBge3IgbWFrZS1zUk5BLWRlc2VxLW9iamVjdCwgY2FjaGU9VFJVRX0KIyBDYWxjdWxhdGUgREVTZXEgb2JqZWN0ClB0dWhfY291bnRzX3NSTkFfcm93TmFtZXMgPC0gUHR1aF9jb3VudHNfc1JOQSAKIyU+JSBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQoKZGRzX1B0dWhfc1JOQSA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IFB0dWhfY291bnRzX3NSTkFfcm93TmFtZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBQdHVoX21ldGFkYXRhX3NSTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gMSkgCgojIFJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyAKIyAoTm90ZSB0aGF0IHRoaXMgREVTZXEoKSBmdW5jdGlvbiBydW5zIGFsbCBuZWNlc3Nhcnkgc3RlcHMsIGluY2x1ZGluZyBkYXRhIG5vcm1hbGl6YXRpb24sIAojIGVzdGltYXRpbmcgc2l6ZSBmYWN0b3JzLCBlc3RpbWF0aW5nIGRpc3BlcnNpb25zLCBnZW5lLXdpc2UgZGlzcGVyc2lvbiBlc3RpbWF0ZXMsIG1lYW4tZGlzcGVyc2lvbiAKIyByZWxhdGlvbnNoaXAsIGZpbmFsIGRpc3BlcnNpb24gZXN0aW1hdGVzLCBmaXR0aW5nIG1vZGVsLCBhbmQgdGVzdGluZykKIyBVc2luZyBkZXNpZ24gPSB+MSBiZWNhdXNlIHdlIGRvbid0IGhhdmUgdHJlYXRtZW50IGdyb3VwcwoKZGRzX1B0dWhfc1JOQSA8LSBERVNlcShkZHNfUHR1aF9zUk5BKQpgYGAKCkl0J3Mgd29ydGggbm90aW5nIGhlcmUgdGhhdCBJJ20gYWN0dWFsbHkgZ29pbmcgdG8gYmUgZG9pbmcgdHdvIGRpZmZlcmVudCB0eXBlcyBvZiB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgY291bnRzIGRhdGEsIHdoaWNoIHNlcnZlIGRpZmZlcmVudCBwdXJwb3Nlcy4gCgotIEZpcnN0IGlzICoqbm9ybWFsaXppbmcqKiB0aGUgdHJhbnNjcmlwdCBjb3VudHMsIHdoaWNoIGFkanVzdHMgZm9yIGRpZmZlcmVuY2VzIGluIGxpYnJhcnkgc2l6ZSBvciBzZXF1ZW5jaW5nIGRlcHRoLCBidXQgcmV0YWlucyBjb3VudC1saWtlIHByb3BlcnRpZXMuIE5vcm1hbGl6ZWQgY291bnRzIGFyZSBtb3N0IHVzZWZ1bCBmb3IgdGhpbmdzIGxpa2UgdmlzdWFsaXppbmcgZXhwcmVzc2lvbiBsZXZlbHMgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLgoKLSBTZWNvbmQgaXMgKip2YXJpYW5jZSBzdGFiaWxpemluZyoqIHRoZSBjb3VudHMgZGF0YSwgd2hpY2ggYWltcyB0byBtYWtlIHRoZSB2YXJpYW5jZSBvZiB0aGUgdHJhbnNmb3JtZWQgZGF0YSBhcHByb3hpbWF0ZWx5IGluZGVwZW5kZW50IG9mIHRoZSBtZWFuLCByZWR1Y2luZyBoZXRlcm9zY2VkYXN0aWNpdHkgKHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYW5jZSBhbmQgbWVhbikgYW5kICJzbW9vdGhpbmciIG91dCB0aGUgdmFyaWFuY2UgYXQgbG93IGNvdW50cy4gTm90YWJseSwgdGhlIHRyYW5zZm9ybWVkIGRhdGEgaXMgKm5vIGxvbmdlciBvbiB0aGUgb3JpZ2luYWwgY291bnQgc2NhbGUqLiBUaGUgdHJhbnNmb3JtYXRpb24gbWFrZXMgdGhlIHZhcmlhbmNlIHJvdWdobHkgY29uc3RhbnQgYWNyb3NzIHRoZSByYW5nZSBvZiBjb3VudHMsIHdoaWNoIG1ha2VzIGl0IGVhc2llciB0byBpbnRlcnByZXQgcGF0dGVybnMgaW4gdGhlIGRhdGEgdmlzdWFsbHkuIFZhcmlhbmNlIHN0YWJpbGl6ZWQgZGF0YSBpcyBtb3N0IHVzZWZ1bCBmb3IgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcywgbGlrZSBQQ0EsIGNsdXN0ZXJpbmcsIGFuZCBoZWF0bWFwcywgYW5kIGlzIGFsc28gdGhlIHRyYW5zZm9ybWF0aW9uIHdlJ2xsIHdhbnQgdG8gdXNlIGJlZm9yZSBXR0NOQS4KCmBgYHtyIGdldC1ub3JtYWxpemVkLXNSTkEtY291bnRzLCBjYWNoZT1UUlVFfQojIGV4dHJhY3Qgbm9ybWFsaXplZCBjb3VudHMKIyAobm9ybWFsaXphdGlvbiBpcyBhdXRvbWF0aWNhbGx5IHBlcmZvcm1lZCBieSBkZXNlcTIpClB0dWhfY291bnRzX3NSTkFfbm9ybSA8LSBjb3VudHMoZGRzX1B0dWhfc1JOQSwgbm9ybWFsaXplZD1UUlVFKSAlPiUgZGF0YS5mcmFtZSgpCgp3cml0ZS50YWJsZShQdHVoX2NvdW50c19zUk5BX25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtUHR1aC1zUk5BLXN1bW1hcnkvUHR1aF9jb3VudHNfc1JOQV9ub3JtYWxpemVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCgoKIyB2YXJpYW5jZSBzdGFiaWxpemVkIGRhdGEKdnNkX1B0dWhfc1JOQSA8LSB2YXJpYW5jZVN0YWJpbGl6aW5nVHJhbnNmb3JtYXRpb24oZGRzX1B0dWhfc1JOQSwgYmxpbmQ9VFJVRSkKd3BuX3ZzZF9QdHVoX3NSTkEgPC0gZ2V0VmFyaWFuY2VTdGFiaWxpemVkRGF0YShkZHNfUHR1aF9zUk5BKQpydl93cG5fUHR1aF9zUk5BIDwtIHJvd1ZhcnMod3BuX3ZzZF9QdHVoX3NSTkEsIHVzZU5hbWVzPVRSVUUpCgpQdHVoX2NvdW50c19zUk5BX3ZzZCA8LSBkYXRhLmZyYW1lKHdwbl92c2RfUHR1aF9zUk5BKQp3cml0ZS50YWJsZShQdHVoX2NvdW50c19zUk5BX3ZzZCwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1QdHVoLXNSTkEtc3VtbWFyeS9QdHVoX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCgpxNzVfd3BuX1B0dWhfc1JOQSA8LSBxdWFudGlsZShyb3dWYXJzKHdwbl92c2RfUHR1aF9zUk5BLCB1c2VOYW1lcz1UUlVFKSwgLjc1KSAgIyA3NXRoIHF1YW50aWxlIHZhcmlhYmlsaXR5ClB0dWhfY291bnRzX3NSTkFfdnNkX3E3NSA8LSB3cG5fdnNkX1B0dWhfc1JOQVsgcnZfd3BuX1B0dWhfc1JOQSA+IHE3NV93cG5fUHR1aF9zUk5BLCBdICU+JSBkYXRhLmZyYW1lICMgZmlsdGVyIHRvIHJldGFpbiBvbmx5IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzCndyaXRlLnRhYmxlKFB0dWhfY291bnRzX3NSTkFfdnNkX3E3NSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1QdHVoLXNSTkEtc3VtbWFyeS9QdHVoX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZF9xNzUudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQoKcTk1X3dwbl9QdHVoX3NSTkEgPC0gcXVhbnRpbGUocm93VmFycyh3cG5fdnNkX1B0dWhfc1JOQSwgdXNlTmFtZXM9VFJVRSksIC45NSkgICMgOTV0aCBxdWFudGlsZSB2YXJpYWJpbGl0eQpQdHVoX2NvdW50c19zUk5BX3ZzZF9xOTUgPC0gd3BuX3ZzZF9QdHVoX3NSTkFbIHJ2X3dwbl9QdHVoX3NSTkEgPiBxOTVfd3BuX1B0dWhfc1JOQSwgXSAlPiUgZGF0YS5mcmFtZSAjIGZpbHRlciB0byByZXRhaW4gb25seSB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcwp3cml0ZS50YWJsZShQdHVoX2NvdW50c19zUk5BX3ZzZF9xOTUsIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtUHR1aC1zUk5BLXN1bW1hcnkvUHR1aF9jb3VudHNfc1JOQV92YXJpYW5jZXN0YWJpbGl6ZWRfcTk1LnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKYGBgCgojIyBQbG90IG5vcm1hbGl6ZWQgZGF0YQoKYGBge3IgcGxvdC1ub3JtYWxpemVkLXNSTkF9ClB0dWhfY291bnRzX3NSTkFfbm9ybV9sb25nIDwtIFB0dWhfY291bnRzX3NSTkFfbm9ybSAlPiUKICBtdXRhdGUoCiAgICBHZW5lX2lkID0gcm93Lm5hbWVzKFB0dWhfY291bnRzX3NSTkFfbm9ybSkKICApICU+JQogIHBpdm90X2xvbmdlcigtR2VuZV9pZCkKClB0dWhfY291bnRzX3NSTkFfbm9ybV9sb25nICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG5hbWUsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoIGFuZ2xlID0gOTApCiAgKSArCiAgeWxpbSgwLCBOQSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJOb3JtYWxpemVkIEV4cHJlc3Npb24iLAogICAgeCA9ICJTYW1wbGUiLAogICAgeSA9ICJOb3JtYWxpemVkIGNvdW50cyIKICApCmBgYAoKCiMjIFBsb3QgdmFyaWFuY2Ugc3RhYmlsaXplZCBkYXRhCgpgYGB7ciBwbG90LXZzZC1zUk5BfQpQdHVoX2NvdW50c19zUk5BX3ZzZF9sb25nIDwtIFB0dWhfY291bnRzX3NSTkFfdnNkICU+JQogIG11dGF0ZSgKICAgIEdlbmVfaWQgPSByb3cubmFtZXMoUHR1aF9jb3VudHNfc1JOQV92c2QpCiAgKSAlPiUKICBwaXZvdF9sb25nZXIoLUdlbmVfaWQpCgpQdHVoX2NvdW50c19zUk5BX3ZzZF9sb25nICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG5hbWUsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoIGFuZ2xlID0gOTApCiAgKSArCiAgeWxpbSgwLCBOQSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWYXJpYW5jZSBTdGFiaWxpemVkIEV4cHJlc3Npb24iLAogICAgeCA9ICJTYW1wbGUiLAogICAgeSA9ICJWYXJpYW5jZSBzdGFiaWxpemVkIGRhdGEiCiAgKQpgYGAKCiMjIE5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscyBpbiBlYWNoIHNhbXBsZQoKYGBge3Igbm9ybS1leHByZXNzaW9uLWxldmVsLWhpc3RvZ3JhbXN9CiMgTWVsdCB0aGUgY291bnQgbWF0cml4IGludG8gbG9uZyBmb3JtYXQKUHR1aF9jb3VudHNfbm9ybV9tZWx0ZWQgPC0gbWVsdChQdHVoX2NvdW50c19zUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChQdHVoX2NvdW50c19ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIG5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfbm9ybSA8LSBjb2xTdW1zKFB0dWhfY291bnRzX3NSTkFfbm9ybSkKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKdG90YWxfdHJhbnNjcmlwdHNfbm9ybV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHRvdGFsX3RyYW5zY3JpcHRzX25vcm0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFscyA9IHRvdGFsX3RyYW5zY3JpcHRzX25vcm0pCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KHRvdGFsX3RyYW5zY3JpcHRzX25vcm1fZGYsIGFlcyh4ID0gc2FtcGxlLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWxzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIFRyYW5zY3JpcHRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKIyMgUENBIG9mIHZhcmlhbmNlIHN0YWJpbGl6ZWQgZGF0YQoKYGBge3IgUENBfQpwbG90UENBKHZzZF9QdHVoX3NSTkEsIGludGdyb3VwPSJTYW1wbGUiKQpgYGAKCiMjIFNhbXBsZSBjbHVzdGVyaW5nCgpgYGB7ciBzYW1wbGUtY2x1c3RlcmluZ30Kc2FtcGxlX2Rpc3RzIDwtIGRpc3QodChhc3NheSh2c2RfUHR1aF9zUk5BKSkpCnBoZWF0bWFwKGFzLm1hdHJpeChzYW1wbGVfZGlzdHMpLCBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJldWNsaWRlYW4iLCBtYWluPSJTYW1wbGUgQ2x1c3RlcmluZyIpCmBgYAoKIyMgSGVhdG1hcHMKCk9mIG1vc3QgdmFyaWFibGUgdmFyaWFuY2Ugc3RhYmlsaXplZCBzUk5BIHRyYW5zY3JpcHRzCgpgYGB7ciBoZWF0bXBhc30KIyA3NXRoIHF1YW50aWxlCmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCnBoZWF0bWFwKFB0dWhfY291bnRzX3NSTkFfdnNkX3E3NSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywKICAgICAgICAgc2NhbGU9InJvdyIpCgojIDk1dGggcXVhbnRpbGUKcGhlYXRtYXAoUHR1aF9jb3VudHNfc1JOQV92c2RfcTk1LCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLAogICAgICAgICBzY2FsZT0icm93IikKYGBgCgojIE5vcm1hbGl6ZWQgbWlSTkEgY291bnRzCgojIyBJc29sYXRlIG5vcm1hbGl6ZWQvdnNkIG1pUk5BCmBgYHtyIG1pUk5BLW5vcm1hbGl6ZWQtbWlSTkF9CiMjIEFsc28gd3JpdHRlbiB0byB1c2UgZ2l2ZW4gbWlSTkEgbmFtZXMgIyMKIyBQdHVoX2NvdW50c19zUk5BX25vcm0kTmFtZSA8LSByb3duYW1lcyhQdHVoX2NvdW50c19zUk5BX25vcm0pCiMgUHR1aF9jb3VudHNfbWlSTkFfbm9ybSA8LSBsZWZ0X2pvaW4oUHR1aF9tZXRhZGF0YV9taVJOQSwgUHR1aF9jb3VudHNfc1JOQV9ub3JtLCBieSA9IGMoIk5hbWUiID0gIk5hbWUiKSkgJT4lCiMgICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJnaXZlbl9taVJOQV9uYW1lIikgJT4lCiMgICBzZWxlY3Qoc3RhcnRzX3dpdGgoInNhbXBsZSIpKQojIHdyaXRlLnRhYmxlKFB0dWhfY291bnRzX21pUk5BX25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtUHR1aC1zUk5BLXN1bW1hcnkvUHR1aF9jb3VudHNfbWlSTkFfbm9ybWFsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCiMgCiMgUHR1aF9jb3VudHNfc1JOQV92c2QkTmFtZSA8LSByb3duYW1lcyhQdHVoX2NvdW50c19zUk5BX3ZzZCkKIyBQdHVoX2NvdW50c19taVJOQV92c2QgPC0gbGVmdF9qb2luKFB0dWhfbWV0YWRhdGFfbWlSTkEsIFB0dWhfY291bnRzX3NSTkFfdnNkLCBieSA9IGMoIk5hbWUiID0gIk5hbWUiKSkgJT4lCiMgICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJnaXZlbl9taVJOQV9uYW1lIikgJT4lCiMgICBzZWxlY3Qoc3RhcnRzX3dpdGgoInNhbXBsZSIpKQojIHdyaXRlLnRhYmxlKFB0dWhfY291bnRzX21pUk5BX3ZzZCwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1QdHVoLXNSTkEtc3VtbWFyeS9QdHVoX2NvdW50c19taVJOQV92YXJpYW5jZXN0YWJpbGl6ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQoKIyMgVXNlIGJlbG93IHVudGlsIHlvdSBoYXZlIG1pUk5BIG5hbWVzICMjClB0dWhfY291bnRzX3NSTkFfbm9ybSROYW1lIDwtIHJvd25hbWVzKFB0dWhfY291bnRzX3NSTkFfbm9ybSkKUHR1aF9jb3VudHNfc1JOQV92c2QkTmFtZSA8LSByb3duYW1lcyhQdHVoX2NvdW50c19zUk5BX3ZzZCkKClB0dWhfY291bnRzX21pUk5BX25hbWVzZGYgPC0gZGF0YS5mcmFtZShOYW1lID0gcm93bmFtZXMoUHR1aF9jb3VudHNfbWlSTkEpKSAKClB0dWhfY291bnRzX21pUk5BX25vcm0gPC0gbGVmdF9qb2luKFB0dWhfY291bnRzX21pUk5BX25hbWVzZGYsIFB0dWhfY291bnRzX3NSTkFfbm9ybSwgYnkgPSBjKCJOYW1lIiA9ICJOYW1lIikpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiTmFtZSIpCndyaXRlLnRhYmxlKFB0dWhfY291bnRzX21pUk5BX25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEtUHR1aC1zUk5BLXN1bW1hcnkvUHR1aF9jb3VudHNfbWlSTkFfbm9ybWFsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCgpQdHVoX2NvdW50c19taVJOQV92c2QgPC0gbGVmdF9qb2luKFB0dWhfY291bnRzX21pUk5BX25hbWVzZGYsIFB0dWhfY291bnRzX3NSTkFfdnNkLCBieSA9IGMoIk5hbWUiID0gIk5hbWUiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJOYW1lIikKd3JpdGUudGFibGUoUHR1aF9jb3VudHNfbWlSTkFfdnNkLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLVB0dWgtc1JOQS1zdW1tYXJ5L1B0dWhfY291bnRzX21pUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgTm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBtaVJOQS1ub3JtLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApQdHVoX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCA8LSBtZWx0KFB0dWhfY291bnRzX21pUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChQdHVoX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM3QTIwNDgiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIG1pUk5BLW5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfbWlSTkFfbm9ybSA8LSBjb2xTdW1zKFB0dWhfY291bnRzX21pUk5BX25vcm0pCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX21pUk5BX25vcm1fZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtX2RmLCBhZXMoeCA9IHNhbXBsZSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjN0EyMDQ4IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFscyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIG1pUk5BIFRyYW5zY3JpcHRzIHBlciBTYW1wbGUiLAogICAgICAgeCA9ICJTYW1wbGUiLAogICAgICAgeSA9ICJUb3RhbCBUcmFuc2NyaXB0cyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIEhlYXRtYXAKCk9mIGFsbCBtaVJOQXMKCmBgYHtyIG1pUk5BLWhlYXRtYXBzLXZzZH0KaGVhdF9jb2xvcnMgPC0gcmV2KGJyZXdlci5wYWwoMTIsICJSZFlsQnUiKSkKcGhlYXRtYXAoYXMubWF0cml4KFB0dWhfY291bnRzX21pUk5BX3ZzZFthcHBseShQdHVoX2NvdW50c19taVJOQV92c2QsIDEsIHZhcikgPiAwLCBdKSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywKICAgICAgICAgc2NhbGU9InJvdyIpCgpgYGAKCgojIE5vcm1hbGl6ZWQgc2lSTkEgY291bnRzCgojIyBJc29sYXRlIG5vcm1hbGl6ZWQvdnNkIHNpUk5BCmBgYHtyIHNpUk5BLW5vcm1hbGl6ZWQtc2lSTkF9CgpQdHVoX2NvdW50c19zUk5BX25vcm0kTmFtZSA8LSByb3duYW1lcyhQdHVoX2NvdW50c19zUk5BX25vcm0pClB0dWhfY291bnRzX3NSTkFfdnNkJE5hbWUgPC0gcm93bmFtZXMoUHR1aF9jb3VudHNfc1JOQV92c2QpCgpQdHVoX2NvdW50c19zaVJOQV9uYW1lc2RmIDwtIGRhdGEuZnJhbWUoTmFtZSA9IHJvd25hbWVzKFB0dWhfY291bnRzX3NpUk5BKSkgCgpQdHVoX2NvdW50c19zaVJOQV9ub3JtIDwtIGxlZnRfam9pbihQdHVoX2NvdW50c19zaVJOQV9uYW1lc2RmLCBQdHVoX2NvdW50c19zUk5BX25vcm0sIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQp3cml0ZS50YWJsZShQdHVoX2NvdW50c19zaVJOQV9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wMy4xLVB0dWgtc1JOQS1zdW1tYXJ5L1B0dWhfY291bnRzX3NpUk5BX25vcm1hbGl6ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQoKUHR1aF9jb3VudHNfc2lSTkFfdnNkIDwtIGxlZnRfam9pbihQdHVoX2NvdW50c19zaVJOQV9uYW1lc2RmLCBQdHVoX2NvdW50c19zUk5BX3ZzZCwgYnkgPSBjKCJOYW1lIiA9ICJOYW1lIikpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiTmFtZSIpCndyaXRlLnRhYmxlKFB0dWhfY291bnRzX3NpUk5BX3ZzZCwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMS1QdHVoLXNSTkEtc3VtbWFyeS9QdHVoX2NvdW50c19zaVJOQV92YXJpYW5jZXN0YWJpbGl6ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQpgYGAKCiMjIE5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscyBpbiBlYWNoIHNhbXBsZQoKYGBge3Igc2lSTkEtbm9ybS1leHByZXNzaW9uLWxldmVsLWhpc3RvZ3JhbXN9CiMgTWVsdCB0aGUgY291bnQgbWF0cml4IGludG8gbG9uZyBmb3JtYXQKUHR1aF9jb3VudHNfc2lSTkFfbm9ybV9tZWx0ZWQgPC0gbWVsdChQdHVoX2NvdW50c19zaVJOQV9ub3JtLCB2YXJpYWJsZS5uYW1lID0gInNhbXBsZSIsIHZhbHVlLm5hbWUgPSAiY291bnRzIikKCiMgUGxvdCB0aGUgZXhwcmVzc2lvbiBsZXZlbCBoaXN0b2dyYW1zIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QoUHR1aF9jb3VudHNfc2lSTkFfbm9ybV9tZWx0ZWQsIGFlcyh4ID0gY291bnRzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICIjN0EyMDQ4IiwgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgICMgT3B0aW9uYWw6IExvZy10cmFuc2Zvcm0gdGhlIHgtYXhpcyBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24KICBmYWNldF93cmFwKH5zYW1wbGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh0aXRsZSA9ICJHZW5lIEV4cHJlc3Npb24gTGV2ZWwgSGlzdG9ncmFtIGZvciBFYWNoIFNhbXBsZSIsCiAgICAgICB4ID0gIkV4cHJlc3Npb24gTGV2ZWwgKENvdW50cykiLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgTm9ybWFsaXplZCB0cmFuc2NyaXB0IGNvdW50cwoKQ2hlY2sgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBpbiBlYWNoIHNhbXBsZSAtLSBub3cgdGhhdCB3ZSd2ZSBub3JtYWxpemVkIHRoZSBkYXRhIHRoZXNlIHRvdGFscyBzaG91bGQgYmUgc2ltaWxhcgpgYGB7ciBzaVJOQS1ub3JtLXRyYW5zY3JpcHQtY291bnRzLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCnRvdGFsX3RyYW5zY3JpcHRzX3NpUk5BX25vcm0gPC0gY29sU3VtcyhQdHVoX2NvdW50c19zaVJOQV9ub3JtKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp0b3RhbF90cmFuc2NyaXB0c19zaVJOQV9ub3JtX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModG90YWxfdHJhbnNjcmlwdHNfc2lSTkFfbm9ybSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxzID0gdG90YWxfdHJhbnNjcmlwdHNfc2lSTkFfbm9ybSkKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodG90YWxfdHJhbnNjcmlwdHNfc2lSTkFfbm9ybV9kZiwgYWVzKHggPSBzYW1wbGUsIHkgPSB0b3RhbHMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzdBMjA0OCIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB0b3RhbHMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBzaVJOQSBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgVHJhbnNjcmlwdHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCgojIyBIZWF0bWFwCgpPZiBhbGwgc2lSTkFzCgpgYGB7ciBzaVJOQS1oZWF0bWFwcy12c2R9CmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCnBoZWF0bWFwKGFzLm1hdHJpeChQdHVoX2NvdW50c19zaVJOQV92c2RbYXBwbHkoUHR1aF9jb3VudHNfc2lSTkFfdnNkLCAxLCB2YXIpID4gMCwgXSksIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsCiAgICAgICAgIHNjYWxlPSJyb3ciKQoKYGBgCgo=