Gene expression summary for Acropora pulchra sRNA-seq data.

  • trimmed reads generated in deep-dive project

  • Reads aligned to Acropora pulchra genome

0.0.1 Install and load packages

library(tidyverse)
## Warning in system("timedatectl", intern = TRUE): running command 'timedatectl'
## had status 1
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(reshape2)
## 
## Attaching package: 'reshape2'
## 
## The following object is masked from 'package:tidyr':
## 
##     smiths
library(pheatmap)
library(RColorBrewer)
library(DESeq2)
## Loading required package: S4Vectors
## Loading required package: stats4
## Loading required package: BiocGenerics
## 
## Attaching package: 'BiocGenerics'
## 
## The following objects are masked from 'package:lubridate':
## 
##     intersect, setdiff, union
## 
## The following objects are masked from 'package:dplyr':
## 
##     combine, intersect, setdiff, union
## 
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## 
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
##     match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
##     table, tapply, union, unique, unsplit, which.max, which.min
## 
## 
## Attaching package: 'S4Vectors'
## 
## The following objects are masked from 'package:lubridate':
## 
##     second, second<-
## 
## The following objects are masked from 'package:dplyr':
## 
##     first, rename
## 
## The following object is masked from 'package:tidyr':
## 
##     expand
## 
## The following objects are masked from 'package:base':
## 
##     expand.grid, I, unname
## 
## Loading required package: IRanges
## 
## Attaching package: 'IRanges'
## 
## The following object is masked from 'package:lubridate':
## 
##     %within%
## 
## The following objects are masked from 'package:dplyr':
## 
##     collapse, desc, slice
## 
## The following object is masked from 'package:purrr':
## 
##     reduce
## 
## Loading required package: GenomicRanges
## Loading required package: GenomeInfoDb
## Loading required package: SummarizedExperiment
## Loading required package: MatrixGenerics
## Loading required package: matrixStats
## 
## Attaching package: 'matrixStats'
## 
## The following object is masked from 'package:dplyr':
## 
##     count
## 
## 
## Attaching package: 'MatrixGenerics'
## 
## The following objects are masked from 'package:matrixStats':
## 
##     colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
##     colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
##     colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
##     colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
##     colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
##     colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
##     colWeightedMeans, colWeightedMedians, colWeightedSds,
##     colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
##     rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
##     rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
##     rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
##     rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
##     rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
##     rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
##     rowWeightedSds, rowWeightedVars
## 
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## 
## Attaching package: 'Biobase'
## 
## The following object is masked from 'package:MatrixGenerics':
## 
##     rowMedians
## 
## The following objects are masked from 'package:matrixStats':
## 
##     anyMissing, rowMedians

1 sRNA

1.1 Load count data and coldata

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 Counts generated in 04-Apul-sRNA-discovery-ShortStack. Coldata generated in 03.00-D-Apul-RNAseq-gene-expression-DESeq2

# Read in sRNA counts data
Apul_counts_sRNA_data_OG <- read_delim("../output/04-Apul-sRNA-discovery-ShortStack/ShortStack_out/Counts.txt", delim="\t") 
## Rows: 18885 Columns: 43
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr  (3): Coords, Name, MIRNA
## dbl (40): 1A10-fastp-adapters-polyG-31bp-merged_condensed, 1A12-fastp-adapte...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(Apul_counts_sRNA_data_OG)
## # A tibble: 6 × 43
##   Coords               Name  MIRNA 1A10-fastp-adapters-…¹ 1A12-fastp-adapters-…²
##   <chr>                <chr> <chr>                  <dbl>                  <dbl>
## 1 ntLink_7:3054-3472   Clus… N                          6                     19
## 2 ntLink_7:9758-10311  Clus… N                         12                     47
## 3 ntLink_7:22562-22980 Clus… N                         16                     19
## 4 ntLink_7:29267-29820 Clus… N                         10                     32
## 5 ntLink_7:42050-42468 Clus… N                         18                     19
## 6 ntLink_7:43122-43556 Clus… N                          0                     46
## # ℹ abbreviated names: ¹​`1A10-fastp-adapters-polyG-31bp-merged_condensed`,
## #   ²​`1A12-fastp-adapters-polyG-31bp-merged_condensed`
## # ℹ 38 more variables: `1A1-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
## #   `1A2-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
## #   `1A8-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
## #   `1A9-fastp-adapters-polyG-31bp-merged_condensed` <dbl>,
## #   `1B10-fastp-adapters-polyG-31bp-merged_condensed` <dbl>, …
# Read in coldata 
coldata_OG <- read.csv(file = "../output/03.00-D-Apul-RNAseq-gene-expression-DESeq2/DESeq2-coldata.tab", row.names=1, sep = "\t")
coldata_OG$time.point <- factor(coldata_OG$time.point)

1.2 Count data munging

Apul_counts_sRNA <- Apul_counts_sRNA_data_OG
coldata <- coldata_OG

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

# Keep just the counts and cluster names
Apul_counts_sRNA <- Apul_counts_sRNA %>% select(-Coords, -MIRNA)

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

# Append colony and timepoint info to sample names
colnames(Apul_counts_sRNA) <- paste(colnames(Apul_counts_sRNA), coldata[colnames(Apul_counts_sRNA), "colony.id"], coldata[colnames(Apul_counts_sRNA), "time.point"], sep = "_")
# Make sure coldata metadata has matching rownames (for DEseq2 formatting)
rownames(coldata) <- paste(rownames(coldata), coldata$colony.id, coldata$time.point, sep = "_")


write.table(Apul_counts_sRNA, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_sRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)

head(Apul_counts_sRNA)
##           1A10_ACR-145_TP4 1A12_ACR-237_TP3 1A1_ACR-173_TP1 1A2_ACR-244_TP4
## Cluster_1                6               19              39               6
## Cluster_2               12               47             150              21
## Cluster_3               16               19              48               5
## Cluster_4               10               32             157              28
## Cluster_5               18               19              20               6
## Cluster_6                0               46              53              12
##           1A8_ACR-186_TP2 1A9_ACR-244_TP2 1B10_ACR-150_TP4 1B1_ACR-225_TP3
## Cluster_1               6               9               16              15
## Cluster_2              13              93               58              36
## Cluster_3               6               5                9              14
## Cluster_4              10             105               68              34
## Cluster_5               5               6               14               8
## Cluster_6              40               1               31              44
##           1B2_ACR-173_TP3 1B5_ACR-229_TP1 1B9_ACR-265_TP4 1C10_ACR-173_TP4
## Cluster_1              31              10               3                1
## Cluster_2             109              13               9               27
## Cluster_3              30               6               6                3
## Cluster_4              83              11               9               38
## Cluster_5              31              11               0                5
## Cluster_6              99               9               2               68
##           1C4_ACR-139_TP4 1D10_ACR-265_TP2 1D3_ACR-225_TP4 1D4_ACR-237_TP4
## Cluster_1               2               30              36              51
## Cluster_2               9               63             290             141
## Cluster_3               8               26              44              46
## Cluster_4              12               54             392             131
## Cluster_5               0               33             121              35
## Cluster_6              47                4             273              98
##           1D6_ACR-229_TP2 1D8_ACR-237_TP2 1D9_ACR-229_TP4 1E1_ACR-265_TP3
## Cluster_1               8              26               3               1
## Cluster_2              13             315               6               7
## Cluster_3               9              27               4               3
## Cluster_4              23             202               6              10
## Cluster_5               7              12               7               0
## Cluster_6               2              46              11               6
##           1E3_ACR-150_TP2 1E5_ACR-139_TP3 1E9_ACR-237_TP1 1F11_ACR-173_TP2
## Cluster_1              33               3              12               17
## Cluster_2             107               6              62               36
## Cluster_3              45               1              11                5
## Cluster_4             112               2              72               69
## Cluster_5              44               0               8               13
## Cluster_6               1               0              51                2
##           1F4_ACR-150_TP3 1F8_ACR-145_TP3 1G5_ACR-244_TP3 1H11_ACR-225_TP1
## Cluster_1              30               2               4                9
## Cluster_2             105               8              63               34
## Cluster_3              30               1               3               12
## Cluster_4             117              18              64               31
## Cluster_5              42               1               0                7
## Cluster_6              59               1              30               51
##           1H12_ACR-186_TP3 1H6_ACR-225_TP2 1H7_ACR-229_TP3 1H8_ACR-186_TP4
## Cluster_1                7              48               4               6
## Cluster_2               11             235               7               2
## Cluster_3                8              34              10               8
## Cluster_4               11             299               8               8
## Cluster_5                6              33               3               4
## Cluster_6                4              26              16              53
##           2B2_ACR-145_TP1 2B3_ACR-139_TP2 2C1_ACR-244_TP1 2C2_ACR-139_TP1
## Cluster_1               7              30               1              36
## Cluster_2              13              32              24             156
## Cluster_3              13              27               3              25
## Cluster_4              11              37              26              77
## Cluster_5              24               6               0              61
## Cluster_6               1             293               2             262
##           2D2_ACR-150_TP1 2E2_ACR-186_TP1 2F1_ACR-265_TP1 2G1_ACR-145_TP2
## Cluster_1               7               0               5              46
## Cluster_2              55               4               5             400
## Cluster_3              22               3               3              36
## Cluster_4              85               4               7             408
## Cluster_5              21               5               5              48
## Cluster_6              24               2               0               4
head(coldata)
##                  time.point colony.id
## 1A1_ACR-173_TP1         TP1   ACR-173
## 1A10_ACR-145_TP4        TP4   ACR-145
## 1A12_ACR-237_TP3        TP3   ACR-237
## 1A2_ACR-244_TP4         TP4   ACR-244
## 1A8_ACR-186_TP2         TP2   ACR-186
## 1A9_ACR-244_TP2         TP2   ACR-244

1.3 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")
## No id variables; using all as measure variables
# 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()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 99729 rows containing non-finite outside the scale range
## (`stat_bin()`).

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(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 = reorder(sample, totals), y = totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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

No glaring discrepancies/patterns

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 = reorder(sample, uniques), y = uniques)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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.

Apul_counts_miRNA <- Apul_counts_sRNA_data_OG
coldata <- coldata_OG

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

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

# Keep just the counts and cluster names
Apul_counts_miRNA <- Apul_counts_miRNA %>% select(-Coords, -MIRNA)

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

# Append colony and timepoint info to sample names
colnames(Apul_counts_miRNA) <- paste(colnames(Apul_counts_miRNA), coldata[colnames(Apul_counts_miRNA), "colony.id"], coldata[colnames(Apul_counts_miRNA), "time.point"], sep = "_")
# Make sure coldata metadata has matching rownames (for DEseq2 formatting)
rownames(coldata) <- paste(rownames(coldata), coldata$colony.id, coldata$time.point, sep = "_")

write.table(Apul_counts_miRNA, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_miRNA_ShortStack_counts_formatted.txt", sep = "\t", row.names = TRUE, col.names = TRUE, quote = FALSE)

head(Apul_counts_miRNA)
##              1A10_ACR-145_TP4 1A12_ACR-237_TP3 1A1_ACR-173_TP1 1A2_ACR-244_TP4
## Cluster_1819               37               35             102              77
## Cluster_1832              325              435            1826             947
## Cluster_1833               16               52              40              30
## Cluster_1836             1071             2048            2334            6240
## Cluster_1865              103              299             203             491
## Cluster_1950              121              179             413             421
##              1A8_ACR-186_TP2 1A9_ACR-244_TP2 1B10_ACR-150_TP4 1B1_ACR-225_TP3
## Cluster_1819              84             340               14              19
## Cluster_1832            1238            2174              219             580
## Cluster_1833               6               0                6              27
## Cluster_1836            8001           11364             1614            2024
## Cluster_1865             108            1203               86             119
## Cluster_1950             224             689              201             297
##              1B2_ACR-173_TP3 1B5_ACR-229_TP1 1B9_ACR-265_TP4 1C10_ACR-173_TP4
## Cluster_1819              36             204              25               18
## Cluster_1832             547            3544             223              235
## Cluster_1833              30             145               6                3
## Cluster_1836            1577            5523            1993              885
## Cluster_1865             137             753             114               56
## Cluster_1950             249            1345             130               79
##              1C4_ACR-139_TP4 1D10_ACR-265_TP2 1D3_ACR-225_TP4 1D4_ACR-237_TP4
## Cluster_1819              10               96              66              41
## Cluster_1832             211              618            2897             978
## Cluster_1833              13                0              82              94
## Cluster_1836            1073             2737           14727           10196
## Cluster_1865              74              503             652             337
## Cluster_1950              51              400            1100             269
##              1D6_ACR-229_TP2 1D8_ACR-237_TP2 1D9_ACR-229_TP4 1E1_ACR-265_TP3
## Cluster_1819             195              81              66              19
## Cluster_1832            2836             645            1098             265
## Cluster_1833              30              57              12              21
## Cluster_1836            8094            4832            4571            1210
## Cluster_1865             536             345             253             178
## Cluster_1950            1043             206             460             102
##              1E3_ACR-150_TP2 1E5_ACR-139_TP3 1E9_ACR-237_TP1 1F11_ACR-173_TP2
## Cluster_1819             177               2              19               88
## Cluster_1832            1326              45             288             1527
## Cluster_1833               0               0              19               24
## Cluster_1836            5111             747            1425             4717
## Cluster_1865             669              16             130              174
## Cluster_1950             646              18             223              247
##              1F4_ACR-150_TP3 1F8_ACR-145_TP3 1G5_ACR-244_TP3 1H11_ACR-225_TP1
## Cluster_1819              56              23              95               18
## Cluster_1832             757             214            2749              610
## Cluster_1833              12               7               0               20
## Cluster_1836            3174            1026            4302             1059
## Cluster_1865             454              53            1140              157
## Cluster_1950             280             101             707              384
##              1H12_ACR-186_TP3 1H6_ACR-225_TP2 1H7_ACR-229_TP3 1H8_ACR-186_TP4
## Cluster_1819               33              47              50              28
## Cluster_1832              439            1714             805             873
## Cluster_1833               11              38              11              42
## Cluster_1836             1636            6727            2155            1625
## Cluster_1865               38             602             217              87
## Cluster_1950              147             666             360             421
##              2B2_ACR-145_TP1 2B3_ACR-139_TP2 2C1_ACR-244_TP1 2C2_ACR-139_TP1
## Cluster_1819              44              68              57              50
## Cluster_1832             232            1769             788            1115
## Cluster_1833               0              18              53              24
## Cluster_1836            1266            5844            2033            2926
## Cluster_1865             139             204             344             380
## Cluster_1950             290             657             370             450
##              2D2_ACR-150_TP1 2E2_ACR-186_TP1 2F1_ACR-265_TP1 2G1_ACR-145_TP2
## Cluster_1819              22              24              16              62
## Cluster_1832             144             211             171            1032
## Cluster_1833               4               0               0              27
## Cluster_1836            1267            1729             656            8817
## Cluster_1865              94               7              34             324
## Cluster_1950             127              63              67             255

2.2 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")
## No id variables; using all as measure variables
# 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 = "miRNA Expression Level Histogram for Each Sample",
       x = "Expression Level (Counts)",
       y = "Frequency") +
  theme_minimal()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 159 rows containing non-finite outside the scale range
## (`stat_bin()`).

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(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 = reorder(sample, totals), y = totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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(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 = reorder(sample, uniques), y = uniques)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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(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)

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)

Apul_Resultsgff <- read.table("../output/04-Apul-sRNA-discovery-ShortStack/ShortStack_out/Results.gff3")
# Separate last column info into multiple columns for filtering
Apul_Resultsgff <- Apul_Resultsgff %>%
  separate(V9, into = c("Name", "DicerCall", "MIRNA"), sep = ";") %>%
  mutate(Name = sub("ID=", "", Name),
         DicerCall = sub("DicerCall=", "", DicerCall),
         MIRNA = sub("MIRNA=", "", MIRNA))
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 102 rows [1820, 1821,
## 1835, 1836, 1838, 1839, 1843, 1844, 1874, 1875, 1961, 1962, 1964, 1965, 2387,
## 2388, 2517, 2518, 2765, 2766, ...].
head(Apul_Resultsgff)
##         V1         V2                 V3    V4    V5   V6 V7 V8      Name
## 1 ntLink_7 ShortStack Unknown_sRNA_locus  3054  3472  625  -  . Cluster_1
## 2 ntLink_7 ShortStack Unknown_sRNA_locus  9758 10311 2797  +  . Cluster_2
## 3 ntLink_7 ShortStack Unknown_sRNA_locus 22562 22980  634  -  . Cluster_3
## 4 ntLink_7 ShortStack Unknown_sRNA_locus 29267 29820 2881  +  . Cluster_4
## 5 ntLink_7 ShortStack Unknown_sRNA_locus 42050 42468  689  -  . Cluster_5
## 6 ntLink_7 ShortStack Unknown_sRNA_locus 43122 43556 1774  -  . Cluster_6
##   DicerCall MIRNA
## 1         N     N
## 2         N     N
## 3         N     N
## 4         N     N
## 5         N     N
## 6         N     N
# keep just the sRNA category column (V3), and the cluster names (Name)
# filter to only keep clusters ID'd as siRNAs
Apul_siRNA_clusters <- Apul_Resultsgff %>%
  select(V3, Name) %>%
  filter(str_detect(V3, regex("siRNA")))
head(Apul_siRNA_clusters)
##              V3         Name
## 1 siRNA23_locus   Cluster_74
## 2 siRNA23_locus  Cluster_232
## 3 siRNA23_locus  Cluster_238
## 4 siRNA23_locus  Cluster_938
## 5 siRNA24_locus  Cluster_967
## 6 siRNA21_locus Cluster_1810
# Now use this list of clusters ID'd as siRNAs to filter our sRNA count matrix
# keep only the sample counts and cluster names
Apul_counts_sRNA <- rownames_to_column(Apul_counts_sRNA, var = "Name")
Apul_counts_siRNA <- left_join(Apul_siRNA_clusters, Apul_counts_sRNA, by = c("Name" = "Name")) %>%
  select(-V3)

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

head(Apul_counts_siRNA)
##              1A10_ACR-145_TP4 1A12_ACR-237_TP3 1A1_ACR-173_TP1 1A2_ACR-244_TP4
## Cluster_74                  8                3              29              10
## Cluster_232                 0                3              11              15
## Cluster_238                 0                5              11              16
## Cluster_938                 2                3               1               1
## Cluster_967                14               15              22              18
## Cluster_1810               10               20              37              14
##              1A8_ACR-186_TP2 1A9_ACR-244_TP2 1B10_ACR-150_TP4 1B1_ACR-225_TP3
## Cluster_74                 0              19                1              28
## Cluster_232                6              62                0               0
## Cluster_238                5              68                2               0
## Cluster_938               60              29                0               0
## Cluster_967               29              26               10               6
## Cluster_1810              56             131               25              10
##              1B2_ACR-173_TP3 1B5_ACR-229_TP1 1B9_ACR-265_TP4 1C10_ACR-173_TP4
## Cluster_74                 8              65               9                4
## Cluster_232               11               1               0                3
## Cluster_238               12               1               0                3
## Cluster_938                1              17               0                2
## Cluster_967                9              57              13               10
## Cluster_1810              11              91               8                4
##              1C4_ACR-139_TP4 1D10_ACR-265_TP2 1D3_ACR-225_TP4 1D4_ACR-237_TP4
## Cluster_74                 2                7             272              22
## Cluster_232               30                1               0               6
## Cluster_238               31                0               1               7
## Cluster_938                1               19              13               5
## Cluster_967                7               24              62              17
## Cluster_1810               8               72              43              30
##              1D6_ACR-229_TP2 1D8_ACR-237_TP2 1D9_ACR-229_TP4 1E1_ACR-265_TP3
## Cluster_74                33               7              27               2
## Cluster_232                1               8               1               0
## Cluster_238                1               9               1               0
## Cluster_938              116               8               2               2
## Cluster_967               40              17              13              14
## Cluster_1810              84              54              21               8
##              1E3_ACR-150_TP2 1E5_ACR-139_TP3 1E9_ACR-237_TP1 1F11_ACR-173_TP2
## Cluster_74                12               1               4               10
## Cluster_232                0              10               1               14
## Cluster_238                0               9               1               11
## Cluster_938              207               0               3                3
## Cluster_967               59               4               8               17
## Cluster_1810             111               3              27               53
##              1F4_ACR-150_TP3 1F8_ACR-145_TP3 1G5_ACR-244_TP3 1H11_ACR-225_TP1
## Cluster_74                 8               2              19               37
## Cluster_232                4               0              26                0
## Cluster_238                4               0              27                0
## Cluster_938               11               2               8                2
## Cluster_967               11               8              39               20
## Cluster_1810              42              15              30               22
##              1H12_ACR-186_TP3 1H6_ACR-225_TP2 1H7_ACR-229_TP3 1H8_ACR-186_TP4
## Cluster_74                  7              66              12              10
## Cluster_232                 1               0               3               2
## Cluster_238                 1               0               2               3
## Cluster_938                 1              21               5              13
## Cluster_967                 8              27               8              26
## Cluster_1810                5              66              32              18
##              2B2_ACR-145_TP1 2B3_ACR-139_TP2 2C1_ACR-244_TP1 2C2_ACR-139_TP1
## Cluster_74                10              23              29              21
## Cluster_232                1             126              15             205
## Cluster_238                0             124              16             203
## Cluster_938                2              13               4               5
## Cluster_967               38              45              24              41
## Cluster_1810              27              98              28              42
##              2D2_ACR-150_TP1 2E2_ACR-186_TP1 2F1_ACR-265_TP1 2G1_ACR-145_TP2
## Cluster_74                 4               8               3               5
## Cluster_232                6               1               0               4
## Cluster_238                6               1               0               5
## Cluster_938                1               2               1              22
## Cluster_967                5               9               5              21
## Cluster_1810               9               8               6              49
write.table(Apul_counts_siRNA, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_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
Apul_counts_siRNA_melted <- melt(Apul_counts_siRNA, variable.name = "sample", value.name = "counts")
## No id variables; using all as measure variables
# Plot the expression level histograms for each sample
ggplot(Apul_counts_siRNA_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 = "siRNA Expression Level Histogram for Each Sample",
       x = "Expression Level (Counts)",
       y = "Frequency") +
  theme_minimal()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 372 rows containing non-finite outside the scale range
## (`stat_bin()`).

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(Apul_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 = reorder(sample, totals), y = totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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

All of the TP2s seem to have higher #s, but since this isn’t normalized I don’t want to put too much stock in that

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(Apul_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 = reorder(sample, uniques), y = uniques)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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(Apul_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(Apul_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 Metadata

DESeq2 requires a metadata data frame as input – we’ll use the coldata we’ve already formatted

head(coldata)
##                  time.point colony.id
## 1A1_ACR-173_TP1         TP1   ACR-173
## 1A10_ACR-145_TP4        TP4   ACR-145
## 1A12_ACR-237_TP3        TP3   ACR-237
## 1A2_ACR-244_TP4         TP4   ACR-244
## 1A8_ACR-186_TP2         TP2   ACR-186
## 1A9_ACR-244_TP2         TP2   ACR-244

5.1.2 DESeq object

5.2 Verify rownames match

# Alphabetize rownames of coldata and colnames of Apul_counts_sRNA
coldata <- coldata[order(rownames(coldata)), ]
Apul_counts_sRNA <- Apul_counts_sRNA[, order(colnames(Apul_counts_sRNA))]

all(rownames(coldata) == colnames(Apul_counts_sRNA))
## [1] TRUE

6 Create DESeq2 data set

dds_Apul_sRNA <- DESeqDataSetFromMatrix(countData = Apul_counts_sRNA,
                              colData = coldata,
                              design = ~ time.point + colony.id)
## converting counts to integer mode
## Warning in DESeqDataSet(se, design = design, ignoreRank): some variables in
## design formula are characters, converting to factors
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
dds_Apul_sRNA
## class: DESeqDataSet 
## dim: 18885 40 
## metadata(1): version
## assays(1): counts
## rownames(18885): Cluster_1 Cluster_2 ... Cluster_18884 Cluster_18885
## rowData names(0):
## colnames(40): 1A1_ACR-173_TP1 1A10_ACR-145_TP4 ... 2F1_ACR-265_TP1
##   2G1_ACR-145_TP2
## colData names(2): time.point colony.id
dds_Apul_sRNA$time.point <- factor(dds_Apul_sRNA$time.point, levels = c("TP1","TP2", "TP3", "TP4"))

dds_Apul_sRNA <- DESeq(dds_Apul_sRNA)
## estimating size factors
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
## final dispersion estimates
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
## fitting model and testing

6.1 Pairwise results tables

# Define the output directory path
output_dir <- "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/"

# Set desired false discovery rate threshold (i.e. adjusted p-value, padj)
fdr <- 0.05

# Set log2 fold change threshold (a value of '1' is equal to a fold change of '2')
log2fc <- 1

sRNA_tp1.v.tp2.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP1","TP2"), alpha = fdr, lfcThreshold = log2fc)
sRNA_tp1.v.tp3.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP1","TP3"), alpha = fdr, lfcThreshold = log2fc)
sRNA_tp1.v.tp4.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP1","TP4"), alpha = fdr, lfcThreshold = log2fc)
sRNA_tp2.v.tp3.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP2","TP3"), alpha = fdr, lfcThreshold = log2fc)
sRNA_tp2.v.tp4.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP2","TP4"), alpha = fdr, lfcThreshold = log2fc)
sRNA_tp3.v.tp4.results <- results(dds_Apul_sRNA, contrast=c("time.point","TP3","TP4"), alpha = fdr, lfcThreshold = log2fc)

sRNA_tp2.v.tp4.results
## log2 fold change (MLE): time.point TP2 vs TP4 
## Wald test p-value: time.point TP2 vs TP4 
## DataFrame with 18885 rows and 6 columns
##                baseMean log2FoldChange     lfcSE      stat    pvalue      padj
##               <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>
## Cluster_1       13.0128      0.7818140  0.432541  0.000000  1.000000         1
## Cluster_2       55.8529      1.3487948  0.466752  0.747280  0.454894         1
## Cluster_3       13.5530      0.1447121  0.381801  0.000000  1.000000         1
## Cluster_4       57.1718      1.0440902  0.416307  0.105908  0.915655         1
## Cluster_5       13.4828      0.0805211  0.634008  0.000000  1.000000         1
## ...                 ...            ...       ...       ...       ...       ...
## Cluster_18881   20.5241      0.0824002  0.302947 0.0000000  1.000000         1
## Cluster_18882   13.3871      0.6283925  0.673831 0.0000000  1.000000         1
## Cluster_18883  170.0788      1.0252319  0.567332 0.0444746  0.964526         1
## Cluster_18884  205.3327     -0.7523888  0.550953 0.0000000  1.000000         1
## Cluster_18885  195.5333     -0.8148397  0.540692 0.0000000  1.000000         1
summary(sRNA_tp2.v.tp4.results)
## 
## out of 18885 with nonzero total read count
## adjusted p-value < 0.05
## LFC > 1.00 (up)    : 16, 0.085%
## LFC < -1.00 (down) : 199, 1.1%
## outliers [1]       : 0, 0%
## low counts [2]     : 0, 0%
## (mean count < 0)
## [1] see 'cooksCutoff' argument of ?results
## [2] see 'independentFiltering' argument of ?results
table(sRNA_tp2.v.tp4.results$padj < 0.05)
## 
## FALSE  TRUE 
## 18670   215

Write DDS results tables to CSVs

# Create a named list of the data frames
results_list <- list(
  sRNA_tp1.v.tp2.results = sRNA_tp1.v.tp2.results,
  sRNA_tp1.v.tp3.results = sRNA_tp1.v.tp3.results,
  sRNA_tp1.v.tp4.results = sRNA_tp1.v.tp4.results,
  sRNA_tp2.v.tp3.results = sRNA_tp2.v.tp3.results,
  sRNA_tp2.v.tp4.results = sRNA_tp2.v.tp4.results,
  sRNA_tp3.v.tp4.results = sRNA_tp3.v.tp4.results
)

# Loop through the list and write each data frame to a CSV file in the specified directory
for (df_name in names(results_list)) {
  write.csv(results_list[[df_name]], file = paste0(output_dir, df_name, ".table.csv"), row.names = FALSE, quote = FALSE)
}

6.2 Normalizations

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.10-D-Apul-sRNAseq-expression-DESeq2/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.10-D-Apul-sRNAseq-expression-DESeq2/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.10-D-Apul-sRNAseq-expression-DESeq2/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.10-D-Apul-sRNAseq-expression-DESeq2/Apul_counts_sRNA_variancestabilized_q95.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

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

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

6.5 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")
## No id variables; using all as measure variables
# 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()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 99729 rows containing non-finite outside the scale range
## (`stat_bin()`).

6.6 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 = reorder(sample, totals), y = totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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

6.7 PCA of variance stabilized data

plotPCA(vsd_Apul_sRNA, intgroup="time.point")

plotPCA(vsd_Apul_sRNA, intgroup="colony.id")

Samples are strongly clustering by colony. Interestingly time point doesn’t appear to influence clustering.

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

Samples are strongly clustering by colony.

6.9 Heatmaps

Of most variable variance stabilized sRNA transcripts

# 75th quantile
heat_colors <- rev(brewer.pal(12, "RdYlBu"))
## Warning in brewer.pal(12, "RdYlBu"): n too large, allowed maximum for palette RdYlBu is 11
## Returning the palette you asked for with that many colors
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")

7 Normalized miRNA counts

7.1 Isolate normalized/vsd miRNA

Apul_counts_sRNA_norm$Name <- rownames(Apul_counts_sRNA_norm)
Apul_counts_sRNA_vsd$Name <- rownames(Apul_counts_sRNA_vsd)

Apul_counts_miRNA_namesdf <- data.frame(Name = rownames(Apul_counts_miRNA)) 

Apul_counts_miRNA_norm <- left_join(Apul_counts_miRNA_namesdf, Apul_counts_sRNA_norm, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Apul_counts_miRNA_norm, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_counts_miRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

Apul_counts_miRNA_vsd <- left_join(Apul_counts_miRNA_namesdf, Apul_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Apul_counts_miRNA_vsd, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_counts_miRNA_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
Apul_counts_miRNA_norm_melted <- melt(Apul_counts_miRNA_norm, variable.name = "sample", value.name = "counts")
## No id variables; using all as measure variables
# 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()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 159 rows containing non-finite outside the scale range
## (`stat_bin()`).

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_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 = reorder(sample, totals), totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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

## PCA of variance stabilized miRNAs

Note that I had to convert the counts to a data frame (instead of a DESeqTransform object) to select only miRNAs, so I can’t use the plotPCA() function.

# Perform PCA
pca_res <- prcomp(t(as.matrix(Apul_counts_miRNA_vsd)))

# Calculate percent variance explained
percentVar <- round(100 * (pca_res$sdev^2 / sum(pca_res$sdev^2)))

## Color by colony ID ##
# Convert PCA results to data frame
pca_df <- as.data.frame(pca_res$x)
pca_df$colony.id <- dds_Apul_sRNA$colony.id

# Create PCA plot with percent variance
ggplot(pca_df, aes(x = PC1, y = PC2, color = colony.id)) +
  geom_point(size = 3) +
  labs(
    x = paste0("PC1: ", percentVar[1], "% variance"),
    y = paste0("PC2: ", percentVar[2], "% variance"),
    title = "PCA of VSD miRNA Counts"
  ) +
  theme_minimal()

## Color by colony ID ##
# Convert PCA results to data frame
pca_df <- as.data.frame(pca_res$x)
pca_df$time.point <- dds_Apul_sRNA$time.point

# Create PCA plot with percent variance
ggplot(pca_df, aes(x = PC1, y = PC2, color = time.point)) +
  geom_point(size = 3) +
  labs(
    x = paste0("PC1: ", percentVar[1], "% variance"),
    y = paste0("PC2: ", percentVar[2], "% variance"),
    title = "PCA of VSD miRNA Counts"
  ) +
  theme_minimal()

Interesting! When considering all sRNAs, they strongly clustered by colony and not time point. However, miRNAs alone show clear clustering by time point (though some influence of colony is still apparent).

7.4 Sample clustering

# Calculate the Euclidean distance matrix
sample_dists <- dist(t(Apul_counts_miRNA_vsd))

# Create the heatmap
pheatmap(
  as.matrix(sample_dists), 
  clustering_distance_rows = "euclidean", 
  clustering_distance_cols = "euclidean", 
  main = "Sample Clustering"
)

7.5 Heatmap

Of all miRNAs

heat_colors <- rev(brewer.pal(12, "RdYlBu"))
## Warning in brewer.pal(12, "RdYlBu"): n too large, allowed maximum for palette RdYlBu is 11
## Returning the palette you asked for with that many colors
pheatmap(as.matrix(Apul_counts_miRNA_vsd[apply(Apul_counts_miRNA_vsd, 1, var) > 0, ]), 
         cluster_rows = FALSE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

# 
# top_20_counts_all <- order(rowMeans(counts(dds,normalized=TRUE)),
#                 decreasing=TRUE)[1:200]
# 
# timepoint_annotation = colData(dds) %>% as.data.frame() %>% select(time.point)
# 
# 
# pheatmap(assay(vsd)[top_20_counts_all,], 
#          cluster_rows=FALSE, 
#          show_rownames=FALSE,
#          cluster_cols=TRUE, 
#          annotation_col = timepoint_annotation)
# Perform clustering based on normalized expression
clustering <- pheatmap(as.matrix(Apul_counts_miRNA_norm), 
                        cluster_rows = TRUE,
                        cluster_cols = TRUE,
                        silent = TRUE)  # Save clustering without plotting

# Convert normalized counts to binary (presence/absence)
binary_counts <- Apul_counts_miRNA_norm > 0
binary_counts <- as.matrix(binary_counts) * 1  # Convert logical to numeric (1/0)

# Generate heatmap with binary values using the precomputed clustering
pheatmap(binary_counts, 
         cluster_rows = clustering$tree_row,  # Use row clustering from normalized data
         cluster_cols = clustering$tree_col,  # Use column clustering from normalized data
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = c("white", "black"))  # White for 0 (absence), black for 1 (presence)

It looks like, of the 51 total miRNAs identified, most are consistently present in all A.pulchra colonies and time points. For 10-15 of the miRNAs, presence/absence is more variable accross colonies and timepoints.

results_df <- as.data.frame(sRNA_tp3.v.tp4.results)
results_df$Name <- rownames(results_df)

# Assuming your metadata frame also has a 'Name' column
# Perform the left join to select only the genes listed in metadata
filtered_results <- dplyr::left_join(Apul_counts_miRNA_namesdf, results_df, by = "Name")

filter(filtered_results, padj < 0.05)
## [1] Name           baseMean       log2FoldChange lfcSE          stat          
## [6] pvalue         padj          
## <0 rows> (or 0-length row.names)

8 Normalized siRNA counts

8.1 Isolate normalized/vsd siRNA

Apul_counts_sRNA_norm$Name <- rownames(Apul_counts_sRNA_norm)
Apul_counts_sRNA_vsd$Name <- rownames(Apul_counts_sRNA_vsd)

Apul_counts_siRNA_namesdf <- data.frame(Name = rownames(Apul_counts_siRNA)) 

Apul_counts_siRNA_norm <- left_join(Apul_counts_siRNA_namesdf, Apul_counts_sRNA_norm, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Apul_counts_siRNA_norm, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_counts_siRNA_normalized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

Apul_counts_siRNA_vsd <- left_join(Apul_counts_siRNA_namesdf, Apul_counts_sRNA_vsd, by = c("Name" = "Name")) %>%
  column_to_rownames(var = "Name")
write.table(Apul_counts_siRNA_vsd, file = "../output/03.10-D-Apul-sRNAseq-expression-DESeq2/Apul_counts_siRNA_variancestabilized.txt", sep = "\t", row.names = TRUE, col.names = TRUE,quote = FALSE)

8.2 Normalized expression levels

Plot histograms of the normalized expression levels in each sample

# Melt the count matrix into long format
Apul_counts_siRNA_norm_melted <- melt(Apul_counts_siRNA_norm, variable.name = "sample", value.name = "counts")
## No id variables; using all as measure variables
# Plot the expression level histograms for each sample
ggplot(Apul_counts_siRNA_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()
## Warning in scale_x_log10(): log-10 transformation introduced infinite values.
## Warning: Removed 372 rows containing non-finite outside the scale range
## (`stat_bin()`).

8.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(Apul_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 = reorder(sample, totals), y = totals)) +
  geom_bar(stat = "identity", fill = "#408EC6", 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

8.4 Heatmap

Of all siRNAs

heat_colors <- rev(brewer.pal(12, "RdYlBu"))
## Warning in brewer.pal(12, "RdYlBu"): n too large, allowed maximum for palette RdYlBu is 11
## Returning the palette you asked for with that many colors
pheatmap(as.matrix(Apul_counts_siRNA_vsd[apply(Apul_counts_siRNA_vsd, 1, var) > 0, ]), 
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         show_rownames = TRUE,
         show_colnames = TRUE,
         color = heat_colors,
         scale="row")

LS0tCnRpdGxlOiAiMDMuMTAtRC1BcHVsLXNSTkFzZXEtZXhwcmVzc2lvbi1ERVNlcTIiCmF1dGhvcjogIkthdGhsZWVuIER1cmtpbiIKZGF0ZTogIjIwMjQtMTItMTkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCi0tLQoKR2VuZSBleHByZXNzaW9uIHN1bW1hcnkgZm9yICpBY3JvcG9yYSBwdWxjaHJhKiBzUk5BLXNlcSBkYXRhLgoKLSAgIHRyaW1tZWQgcmVhZHMgZ2VuZXJhdGVkIGluIGBkZWVwLWRpdmVgIHByb2plY3QKCi0gICBSZWFkcyBhbGlnbmVkIHRvICpBY3JvcG9yYSBwdWxjaHJhKiBnZW5vbWUgCgojIyMgSW5zdGFsbCBhbmQgbG9hZCBwYWNrYWdlcwoKYGBge3IgbG9hZF9saWJyYXJpZXMsIGlubGN1ZGUgPSBUUlVFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShERVNlcTIpCmBgYAoKCiMgc1JOQQoKIyMgTG9hZCBjb3VudCBkYXRhIGFuZCBjb2xkYXRhCgpMb2FkIGluIHRoZSBzUk5BIGNvdW50IG1hdHJpeCBnZW5lcmF0ZWQgdXNpbmcgU2hvcnRTdGFjayA0LjEuMC4gS2VlcCBpbiBtaW5kIHRoaXMgZGF0YSBpbmNsdWRlcyBjb3VudHMgb2YgYWxsIHNSTkFzLCBub3QganVzdCBtaVJOQXMKQ291bnRzIGdlbmVyYXRlZCBpbiBgMDQtQXB1bC1zUk5BLWRpc2NvdmVyeS1TaG9ydFN0YWNrYC4gQ29sZGF0YSBnZW5lcmF0ZWQgaW4gYDAzLjAwLUQtQXB1bC1STkFzZXEtZ2VuZS1leHByZXNzaW9uLURFU2VxMmAKCmBgYHtyIGxvYWQtc1JOQS1jb3VudHN9CiMgUmVhZCBpbiBzUk5BIGNvdW50cyBkYXRhCkFwdWxfY291bnRzX3NSTkFfZGF0YV9PRyA8LSByZWFkX2RlbGltKCIuLi9vdXRwdXQvMDQtQXB1bC1zUk5BLWRpc2NvdmVyeS1TaG9ydFN0YWNrL1Nob3J0U3RhY2tfb3V0L0NvdW50cy50eHQiLCBkZWxpbT0iXHQiKSAKaGVhZChBcHVsX2NvdW50c19zUk5BX2RhdGFfT0cpCgojIFJlYWQgaW4gY29sZGF0YSAKY29sZGF0YV9PRyA8LSByZWFkLmNzdihmaWxlID0gIi4uL291dHB1dC8wMy4wMC1ELUFwdWwtUk5Bc2VxLWdlbmUtZXhwcmVzc2lvbi1ERVNlcTIvREVTZXEyLWNvbGRhdGEudGFiIiwgcm93Lm5hbWVzPTEsIHNlcCA9ICJcdCIpCmNvbGRhdGFfT0ckdGltZS5wb2ludCA8LSBmYWN0b3IoY29sZGF0YV9PRyR0aW1lLnBvaW50KQpgYGAKCiMjIENvdW50IGRhdGEgbXVuZ2luZwoKYGBge3Igc1JOQS1jb3VudC1kYXRhLW11bmdpbmd9CkFwdWxfY291bnRzX3NSTkEgPC0gQXB1bF9jb3VudHNfc1JOQV9kYXRhX09HCmNvbGRhdGEgPC0gY29sZGF0YV9PRwoKIyBSZW1vdmUgZXhjZXNzIHBvcnRpb25zIG9mIHNhbXBsZSBjb2x1bW4gbmFtZXMgdG8ganVzdCAic2FtcGxlIyMjIgpjb2xuYW1lcyhBcHVsX2NvdW50c19zUk5BKSA8LSBzdWIoIi1mYXN0cC1hZGFwdGVycy1wb2x5Ry0zMWJwLW1lcmdlZF9jb25kZW5zZWQiLCAiIiwgY29sbmFtZXMoQXB1bF9jb3VudHNfc1JOQSkpCgojIEtlZXAganVzdCB0aGUgY291bnRzIGFuZCBjbHVzdGVyIG5hbWVzCkFwdWxfY291bnRzX3NSTkEgPC0gQXB1bF9jb3VudHNfc1JOQSAlPiUgc2VsZWN0KC1Db29yZHMsIC1NSVJOQSkKCiMgSSdtIG5vdCBnb2luZyB0byBiZSBkb2luZyBhbnkgcmVtb3ZhbCBvZiBsb3ctY291bnQgc1JOQXMgZm9yIG5vdwoKIyBNYWtlIHRoZSBjbHVzdGVyIG5hbWVzIG91ciBuZXcgcm93IG5hbWVzCkFwdWxfY291bnRzX3NSTkEgPC0gQXB1bF9jb3VudHNfc1JOQSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJOYW1lIikKCiMgQXBwZW5kIGNvbG9ueSBhbmQgdGltZXBvaW50IGluZm8gdG8gc2FtcGxlIG5hbWVzCmNvbG5hbWVzKEFwdWxfY291bnRzX3NSTkEpIDwtIHBhc3RlKGNvbG5hbWVzKEFwdWxfY291bnRzX3NSTkEpLCBjb2xkYXRhW2NvbG5hbWVzKEFwdWxfY291bnRzX3NSTkEpLCAiY29sb255LmlkIl0sIGNvbGRhdGFbY29sbmFtZXMoQXB1bF9jb3VudHNfc1JOQSksICJ0aW1lLnBvaW50Il0sIHNlcCA9ICJfIikKIyBNYWtlIHN1cmUgY29sZGF0YSBtZXRhZGF0YSBoYXMgbWF0Y2hpbmcgcm93bmFtZXMgKGZvciBERXNlcTIgZm9ybWF0dGluZykKcm93bmFtZXMoY29sZGF0YSkgPC0gcGFzdGUocm93bmFtZXMoY29sZGF0YSksIGNvbGRhdGEkY29sb255LmlkLCBjb2xkYXRhJHRpbWUucG9pbnQsIHNlcCA9ICJfIikKCgp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zUk5BLCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX3NSTkFfU2hvcnRTdGFja19jb3VudHNfZm9ybWF0dGVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCgpoZWFkKEFwdWxfY291bnRzX3NSTkEpCmhlYWQoY29sZGF0YSkKYGBgCgoKIyMgRXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgaW4gZWFjaCBzYW1wbGUKCmBgYHtyIGV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19zUk5BX21lbHRlZCA8LSBtZWx0KEFwdWxfY291bnRzX3NSTkEsIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19zUk5BX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBUcmFuc2NyaXB0IGNvdW50cwoKRmlyc3QgbGV0J3MgY2hlY2sgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBpbiBlYWNoIHNhbXBsZSAtLSBrZWVwIGluIG1pbmQgdGhpcyBleHByZXNzaW9uIGRhdGEgaGFzICpub3QqIGJlZW4gbm9ybWFsaXplZCB5ZXQsIHNvIHRoZXJlIG1heSBiZSBkaWZmZXJlbnQgdG90YWxzIGZvciBlYWNoIHNhbXBsZQpgYGB7ciB0cmFuc2NyaXB0LWNvdW50cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQp0b3RhbF90cmFuc2NyaXB0cyA8LSBjb2xTdW1zKEFwdWxfY291bnRzX3NSTkEpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModG90YWxfdHJhbnNjcmlwdHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFscyA9IHRvdGFsX3RyYW5zY3JpcHRzKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19kZiwgYWVzKHggPSByZW9yZGVyKHNhbXBsZSwgdG90YWxzKSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFscyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKyAKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgVHJhbnNjcmlwdHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCk5vIGdsYXJpbmcgZGlzY3JlcGFuY2llcy9wYXR0ZXJucwoKTm93IGxldCdzIGNoZWNrIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIHRoYXQgaXMsIGhvdyBtYW55IHVuaXF1ZSBzUk5BcyBhcmUgZXhwcmVzc2VkIGluIGVhY2ggc2FtcGxlPyBUaGlzIHNob3VsZCBiZSBwcmV0dHkgbXVjaCB0aGUgc2FtZSBhY3Jvc3Mgc2FtcGxlcywgZXZlbiB3aXRob3V0IG5vcm1hbGl6YXRpb24uCgpgYGB7ciB0b3RhbC11bmlxdWUtdHJhbnNjcmlwdHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgKG5vbi16ZXJvIGNvdW50cykgZm9yIGVhY2ggc2FtcGxlCnVuaXF1ZV90cmFuc2NyaXB0cyA8LSBjb2xTdW1zKEFwdWxfY291bnRzX3NSTkEgPiAwKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp1bmlxdWVfdHJhbnNjcmlwdHNfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh1bmlxdWVfdHJhbnNjcmlwdHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWVzID0gdW5pcXVlX3RyYW5zY3JpcHRzKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodW5pcXVlX3RyYW5zY3JpcHRzX2RmLCBhZXMoeCA9IHJlb3JkZXIoc2FtcGxlLCB1bmlxdWVzKSwgeSA9IHVuaXF1ZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzQwOEVDNiIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB1bmlxdWVzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArIAogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIFVuaXF1ZSBFeHByZXNzZWQgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBUcmFuc2NyaXB0cyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKICAgCgojIG1pUk5BCgojIyBMb2FkIG1pUk5BIG1ldGFkYXRhCgpUaGUgU2hvcnRTdGFjayBvdXRwdXQgUmVzdWx0cy50eHQgaW5jbHVkZXMgYWxsIGNsdXN0ZXJzIG9mIHNSTkEgcmVhZHMsIGluY2x1ZGluZyB0aG9zZSBub3QgYW5ub3RhdGVkIGFzIHZhbGlkIG1pUk5Bcy4gTm93IHRoYXQgd2UndmUgbG9va2VkIGF0IGFsbCB0aGUgc1JOQXMgYSBiaXQsIGxldCdzIGZvY3VzIGluIG9uIHRob3NlIGNsYXNzaWZpZWQgYXMgbWlSTkFzLgoKYGBge3IgbWlSTkEtY291bnQtZGF0YS1tdW5naW5nfQpBcHVsX2NvdW50c19taVJOQSA8LSBBcHVsX2NvdW50c19zUk5BX2RhdGFfT0cKY29sZGF0YSA8LSBjb2xkYXRhX09HCgojIFJlbW92ZSBleGNlc3MgcG9ydGlvbnMgb2Ygc2FtcGxlIGNvbHVtbiBuYW1lcyB0byBqdXN0ICJzYW1wbGUjIyMiCmNvbG5hbWVzKEFwdWxfY291bnRzX21pUk5BKSA8LSBzdWIoIi1mYXN0cC1hZGFwdGVycy1wb2x5Ry0zMWJwLW1lcmdlZF9jb25kZW5zZWQiLCAiIiwgY29sbmFtZXMoQXB1bF9jb3VudHNfbWlSTkEpKQoKIyBLZWVwIG9ubHkgdGhlIHNSTkFzIElEJ2QgYXMgdmFsaWQgbWlSTkFzCkFwdWxfY291bnRzX21pUk5BIDwtIEFwdWxfY291bnRzX21pUk5BICU+JSBmaWx0ZXIoTUlSTkEgPT0gIlkiKQoKIyBLZWVwIGp1c3QgdGhlIGNvdW50cyBhbmQgY2x1c3RlciBuYW1lcwpBcHVsX2NvdW50c19taVJOQSA8LSBBcHVsX2NvdW50c19taVJOQSAlPiUgc2VsZWN0KC1Db29yZHMsIC1NSVJOQSkKCiMgTWFrZSB0aGUgY2x1c3RlciBuYW1lcyBvdXIgbmV3IHJvdyBuYW1lcwpBcHVsX2NvdW50c19taVJOQSA8LSBBcHVsX2NvdW50c19taVJOQSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJOYW1lIikKCiMgQXBwZW5kIGNvbG9ueSBhbmQgdGltZXBvaW50IGluZm8gdG8gc2FtcGxlIG5hbWVzCmNvbG5hbWVzKEFwdWxfY291bnRzX21pUk5BKSA8LSBwYXN0ZShjb2xuYW1lcyhBcHVsX2NvdW50c19taVJOQSksIGNvbGRhdGFbY29sbmFtZXMoQXB1bF9jb3VudHNfbWlSTkEpLCAiY29sb255LmlkIl0sIGNvbGRhdGFbY29sbmFtZXMoQXB1bF9jb3VudHNfbWlSTkEpLCAidGltZS5wb2ludCJdLCBzZXAgPSAiXyIpCiMgTWFrZSBzdXJlIGNvbGRhdGEgbWV0YWRhdGEgaGFzIG1hdGNoaW5nIHJvd25hbWVzIChmb3IgREVzZXEyIGZvcm1hdHRpbmcpCnJvd25hbWVzKGNvbGRhdGEpIDwtIHBhc3RlKHJvd25hbWVzKGNvbGRhdGEpLCBjb2xkYXRhJGNvbG9ueS5pZCwgY29sZGF0YSR0aW1lLnBvaW50LCBzZXAgPSAiXyIpCgp3cml0ZS50YWJsZShBcHVsX2NvdW50c19taVJOQSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMTAtRC1BcHVsLXNSTkFzZXEtZXhwcmVzc2lvbi1ERVNlcTIvQXB1bF9taVJOQV9TaG9ydFN0YWNrX2NvdW50c19mb3JtYXR0ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSwgcXVvdGUgPSBGQUxTRSkKCmhlYWQoQXB1bF9jb3VudHNfbWlSTkEpCgpgYGAKCiMjIEV4cHJlc3Npb24gbGV2ZWxzCgpQbG90IGhpc3RvZ3JhbXMgb2YgdGhlIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBtaVJOQS1leHByZXNzaW9uLWxldmVsLWhpc3RvZ3JhbXN9CiMgTWVsdCB0aGUgY291bnQgbWF0cml4IGludG8gbG9uZyBmb3JtYXQKQXB1bF9jb3VudHNfbWlSTkFfbWVsdGVkIDwtIG1lbHQoQXB1bF9jb3VudHNfbWlSTkEsIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19taVJOQV9tZWx0ZWQsIGFlcyh4ID0gY291bnRzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgICMgT3B0aW9uYWw6IExvZy10cmFuc2Zvcm0gdGhlIHgtYXhpcyBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24KICBmYWNldF93cmFwKH5zYW1wbGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh0aXRsZSA9ICJtaVJOQSBFeHByZXNzaW9uIExldmVsIEhpc3RvZ3JhbSBmb3IgRWFjaCBTYW1wbGUiLAogICAgICAgeCA9ICJFeHByZXNzaW9uIExldmVsIChDb3VudHMpIiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIG1pUk5BIGNvdW50cwoKRmlyc3QgbGV0J3MgY2hlY2sgdGhlIHRvdGFsIG51bWJlciBvZiBtaVJOQXMgaW4gZWFjaCBzYW1wbGUgLS0ga2VlcCBpbiBtaW5kIHRoaXMgZXhwcmVzc2lvbiBkYXRhIGhhcyAqbm90KiBiZWVuIG5vcm1hbGl6ZWQgeWV0LCBzbyB0aGVyZSBtYXkgYmUgZGlmZmVyZW50IHRvdGFscyBmb3IgZWFjaCBzYW1wbGUKYGBge3IgbWlSTkEtY291bnRzLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCnRvdGFsX21pUk5BIDwtIGNvbFN1bXMoQXB1bF9jb3VudHNfbWlSTkEpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX21pUk5BX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModG90YWxfbWlSTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFscyA9IHRvdGFsX21pUk5BKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF9taVJOQV9kZiwgYWVzKHggPSByZW9yZGVyKHNhbXBsZSwgdG90YWxzKSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFscyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKyAKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBtaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIG1pUk5BcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCk5vdyBsZXQncyBjaGVjayB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBtaVJOQXMgaW4gZWFjaCBzYW1wbGUgLS0gVGhpcyBzaG91bGQgYmUgcHJldHR5IG11Y2ggdGhlIHNhbWUgYWNyb3NzIHNhbXBsZXMsIGV2ZW4gd2l0aG91dCBub3JtYWxpemF0aW9uLgoKYGBge3IgdG90YWwtdW5pcXVlLW1pUk5BLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIChub24temVybyBjb3VudHMpIGZvciBlYWNoIHNhbXBsZQp1bmlxdWVfbWlSTkEgPC0gY29sU3VtcyhBcHVsX2NvdW50c19taVJOQSA+IDApCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnVuaXF1ZV9taVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHVuaXF1ZV9taVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZXMgPSB1bmlxdWVfbWlSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh1bmlxdWVfbWlSTkFfZGYsIGFlcyh4ID0gcmVvcmRlcihzYW1wbGUsIHVuaXF1ZXMpLCB5ID0gdW5pcXVlcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHVuaXF1ZXMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsgCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVW5pcXVlIEV4cHJlc3NlZCBtaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBtaVJOQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIEhlYXRtYXAKCmBgYHtyIG1pUk5BLWhlYXRtYXB9CnBoZWF0bWFwKEFwdWxfY291bnRzX21pUk5BLAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCksCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgIGZvbnRzaXplX2NvbCA9IDgpCmBgYApXZWxsLi4uIHRoZXJlJ3MgbGlrZSAyIG1pUk5BcyB3aXRoIG11Y2ggaGlnaGVyIGV4cHJlc3Npb24gdGhhbiB0aGUgb3RoZXJzLCB3aGljaCBpcyBtYWtpbmcgdmlzdWFsaXppbmcgcmVsYXRpdmUgZGlmZmVyZW5jZXMgZGlmZmljdWx0LiBMZXQncyByZWRvIHRoZSBoZWF0bWFwLCBub3JtYWxpemluZyBlYWNoIHJvdyB0byB2aWV3IHJlbGF0aXZlIGRpZmZlcmVuY2UgaW4gZXhwcmVzc2lvbiBiZXR3ZWVuIHNhbXBsZXMgKGBzY2FsZT0ncm93J2ApCgpgYGB7ciBtaVJOQS1oZWF0bWFwLXJvd3NjYWxlfQpwaGVhdG1hcChBcHVsX2NvdW50c19taVJOQSwKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBzY2FsZSA9ICdyb3cnLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoNTApLAogICAgICAgICBmb250c2l6ZV9yb3cgPSA4LAogICAgICAgICBmb250c2l6ZV9jb2wgPSA4KQpgYGAKCiMgc2lSTkEKClNob3J0U3RhY2sncyBwcmltYXJ5IHB1cnBvc2UgaXMgdG8gaWRlbnRpZnkgbWlSTkFzIGZyb20gc1JOQS1zZXEgZGF0YSwgYnV0IGl0IGFsc28gYXV0b21hdGljYWxseSBhbm5vdGF0ZXMgc2lSTkEgbG9jaSEgU2luY2Ugc2lSTkEgcG90ZW50aWFsbHkgcGxheSBhbiBpbXBvcnRhbnQgcm9sZSBpbiB0cmFuc3Bvc29uIHNpbGVuY2luZyBpbiBpbnZlcnRlYnJhdGVzLCB3ZSBzaG91bGQgZ2VuZXJhdGUgY291bnQgbWF0cmljZXMgZm9yIHNpUk5BcyBhcyB3ZWxsLiAKCldlIGNhbiBzZWUgY2x1c3RlcnMgYW5ub3RhdGVkIGFzIHNpUk5BcyBpbiB0aGUgYFJlc3VsdHMuZ2ZmM2Agb3V0cHV0IGZpbGUgb2YgU2hvcnRTdGFjayAoc1JOQSBJRCBzaG93biBpbiB0aGUgM3JkIGNvbHVtbikKCmBgYHtyIHNpUk5BLWNvdW50LWRhdGEtbXVuZ2luZ30KQXB1bF9SZXN1bHRzZ2ZmIDwtIHJlYWQudGFibGUoIi4uL291dHB1dC8wNC1BcHVsLXNSTkEtZGlzY292ZXJ5LVNob3J0U3RhY2svU2hvcnRTdGFja19vdXQvUmVzdWx0cy5nZmYzIikKIyBTZXBhcmF0ZSBsYXN0IGNvbHVtbiBpbmZvIGludG8gbXVsdGlwbGUgY29sdW1ucyBmb3IgZmlsdGVyaW5nCkFwdWxfUmVzdWx0c2dmZiA8LSBBcHVsX1Jlc3VsdHNnZmYgJT4lCiAgc2VwYXJhdGUoVjksIGludG8gPSBjKCJOYW1lIiwgIkRpY2VyQ2FsbCIsICJNSVJOQSIpLCBzZXAgPSAiOyIpICU+JQogIG11dGF0ZShOYW1lID0gc3ViKCJJRD0iLCAiIiwgTmFtZSksCiAgICAgICAgIERpY2VyQ2FsbCA9IHN1YigiRGljZXJDYWxsPSIsICIiLCBEaWNlckNhbGwpLAogICAgICAgICBNSVJOQSA9IHN1YigiTUlSTkE9IiwgIiIsIE1JUk5BKSkKaGVhZChBcHVsX1Jlc3VsdHNnZmYpCgojIGtlZXAganVzdCB0aGUgc1JOQSBjYXRlZ29yeSBjb2x1bW4gKFYzKSwgYW5kIHRoZSBjbHVzdGVyIG5hbWVzIChOYW1lKQojIGZpbHRlciB0byBvbmx5IGtlZXAgY2x1c3RlcnMgSUQnZCBhcyBzaVJOQXMKQXB1bF9zaVJOQV9jbHVzdGVycyA8LSBBcHVsX1Jlc3VsdHNnZmYgJT4lCiAgc2VsZWN0KFYzLCBOYW1lKSAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdChWMywgcmVnZXgoInNpUk5BIikpKQpoZWFkKEFwdWxfc2lSTkFfY2x1c3RlcnMpCgojIE5vdyB1c2UgdGhpcyBsaXN0IG9mIGNsdXN0ZXJzIElEJ2QgYXMgc2lSTkFzIHRvIGZpbHRlciBvdXIgc1JOQSBjb3VudCBtYXRyaXgKIyBrZWVwIG9ubHkgdGhlIHNhbXBsZSBjb3VudHMgYW5kIGNsdXN0ZXIgbmFtZXMKQXB1bF9jb3VudHNfc1JOQSA8LSByb3duYW1lc190b19jb2x1bW4oQXB1bF9jb3VudHNfc1JOQSwgdmFyID0gIk5hbWUiKQpBcHVsX2NvdW50c19zaVJOQSA8LSBsZWZ0X2pvaW4oQXB1bF9zaVJOQV9jbHVzdGVycywgQXB1bF9jb3VudHNfc1JOQSwgYnkgPSBjKCJOYW1lIiA9ICJOYW1lIikpICU+JQogIHNlbGVjdCgtVjMpCgojIGNvbnZlcnQgdGhlIGNvbHVtbiBvZiBjbHVzdGVyIG5hbWVzIGludG8gdGhlIGRmIHJvdyBuYW1lcwpBcHVsX2NvdW50c19zUk5BIDwtIEFwdWxfY291bnRzX3NSTkEgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXI9Ik5hbWUiKQpBcHVsX2NvdW50c19zaVJOQSA8LSBBcHVsX2NvdW50c19zaVJOQSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0iTmFtZSIpCgpoZWFkKEFwdWxfY291bnRzX3NpUk5BKQoKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfc2lSTkEsIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEwLUQtQXB1bC1zUk5Bc2VxLWV4cHJlc3Npb24tREVTZXEyL0FwdWxfc2lSTkFfU2hvcnRTdGFja19jb3VudHNfZm9ybWF0dGVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUsIHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgRXhwcmVzc2lvbiBsZXZlbHMKClBsb3QgaGlzdG9ncmFtcyBvZiB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgaW4gZWFjaCBzYW1wbGUKCmBgYHtyIHNpUk5BLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19zaVJOQV9tZWx0ZWQgPC0gbWVsdChBcHVsX2NvdW50c19zaVJOQSwgdmFyaWFibGUubmFtZSA9ICJzYW1wbGUiLCB2YWx1ZS5uYW1lID0gImNvdW50cyIpCgojIFBsb3QgdGhlIGV4cHJlc3Npb24gbGV2ZWwgaGlzdG9ncmFtcyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KEFwdWxfY291bnRzX3NpUk5BX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gInNpUk5BIEV4cHJlc3Npb24gTGV2ZWwgSGlzdG9ncmFtIGZvciBFYWNoIFNhbXBsZSIsCiAgICAgICB4ID0gIkV4cHJlc3Npb24gTGV2ZWwgKENvdW50cykiLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgc2lSTkEgY291bnRzCgpGaXJzdCBsZXQncyBjaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHNpUk5BcyBpbiBlYWNoIHNhbXBsZSAtLSBrZWVwIGluIG1pbmQgdGhpcyBleHByZXNzaW9uIGRhdGEgaGFzICpub3QqIGJlZW4gbm9ybWFsaXplZCB5ZXQsIHNvIHRoZXJlIG1heSBiZSBkaWZmZXJlbnQgdG90YWxzIGZvciBlYWNoIHNhbXBsZQpgYGB7ciBzaVJOQS1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfc2lSTkEgPC0gY29sU3VtcyhBcHVsX2NvdW50c19zaVJOQSkKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKdG90YWxfc2lSTkFfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF9zaVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxzID0gdG90YWxfc2lSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KHRvdGFsX3NpUk5BX2RmLCBhZXMoeCA9IHJlb3JkZXIoc2FtcGxlLCB0b3RhbHMpLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWxzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArIAogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIHNpUk5BcyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgc2lSTkFzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYApBbGwgb2YgdGhlIFRQMnMgc2VlbSB0byBoYXZlIGhpZ2hlciAjcywgYnV0IHNpbmNlIHRoaXMgaXNuJ3Qgbm9ybWFsaXplZCBJIGRvbid0IHdhbnQgdG8gcHV0IHRvbyBtdWNoIHN0b2NrIGluIHRoYXQKCk5vdyBsZXQncyBjaGVjayB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBzaVJOQXMgaW4gZWFjaCBzYW1wbGUgLS0gVGhpcyBzaG91bGQgYmUgcHJldHR5IG11Y2ggdGhlIHNhbWUgYWNyb3NzIHNhbXBsZXMsIGV2ZW4gd2l0aG91dCBub3JtYWxpemF0aW9uLgoKYGBge3IgdG90YWwtdW5pcXVlLXNpUk5BLXBsb3R9CiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgdW5pcXVlIHRyYW5zY3JpcHRzIChub24temVybyBjb3VudHMpIGZvciBlYWNoIHNhbXBsZQp1bmlxdWVfc2lSTkEgPC0gY29sU3VtcyhBcHVsX2NvdW50c19zaVJOQSA+IDApCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnVuaXF1ZV9zaVJOQV9kZiA8LSBkYXRhLmZyYW1lKHNhbXBsZSA9IG5hbWVzKHVuaXF1ZV9zaVJOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZXMgPSB1bmlxdWVfc2lSTkEpCgojIFBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh1bmlxdWVfc2lSTkFfZGYsIGFlcyh4ID0gcmVvcmRlcihzYW1wbGUsIHVuaXF1ZXMpLCB5ID0gdW5pcXVlcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHVuaXF1ZXMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsgCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgVW5pcXVlIEV4cHJlc3NlZCBzaVJOQXMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlVuaXF1ZSBzaVJOQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIEhlYXRtYXAKCmBgYHtyIHNpUk5BLWhlYXRtYXB9CnBoZWF0bWFwKEFwdWxfY291bnRzX3NpUk5BLAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCksCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgIGZvbnRzaXplX2NvbCA9IDgpCmBgYAoKYGBge3Igc2lSTkEtaGVhdG1hcC1yb3dzY2FsZX0KcGhlYXRtYXAoQXB1bF9jb3VudHNfc2lSTkEsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgc2NhbGUgPSAncm93JywKICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDUwKSwKICAgICAgICAgZm9udHNpemVfcm93ID0gOCwKICAgICAgICAgZm9udHNpemVfY29sID0gOCkKYGBgCgoKIyAuLi4uLi4uLi4uLgoKIyBOb3JtYWxpemVkIHNSTkEgY291bnRzCgojIyBOb3JtYWxpemUgY291bnRzIHdpdGggREVTZXEyCgojIyMgTWV0YWRhdGEKCkRFU2VxMiByZXF1aXJlcyBhIG1ldGFkYXRhIGRhdGEgZnJhbWUgYXMgaW5wdXQgLS0gd2UnbGwgdXNlIHRoZSBjb2xkYXRhIHdlJ3ZlIGFscmVhZHkgZm9ybWF0dGVkCgpgYGB7ciBtYWtlLXNSTkEtbWV0YWRhdGEtZGF0YWZyYW1lfQoKaGVhZChjb2xkYXRhKQpgYGAKCiMjIyBERVNlcSBvYmplY3QKCiMjIFZlcmlmeSByb3duYW1lcyBtYXRjaApgYGB7ciBjaGVjay1yb3duYW1lc30KIyBBbHBoYWJldGl6ZSByb3duYW1lcyBvZiBjb2xkYXRhIGFuZCBjb2xuYW1lcyBvZiBBcHVsX2NvdW50c19zUk5BCmNvbGRhdGEgPC0gY29sZGF0YVtvcmRlcihyb3duYW1lcyhjb2xkYXRhKSksIF0KQXB1bF9jb3VudHNfc1JOQSA8LSBBcHVsX2NvdW50c19zUk5BWywgb3JkZXIoY29sbmFtZXMoQXB1bF9jb3VudHNfc1JOQSkpXQoKYWxsKHJvd25hbWVzKGNvbGRhdGEpID09IGNvbG5hbWVzKEFwdWxfY291bnRzX3NSTkEpKQpgYGAKCiMgQ3JlYXRlIERFU2VxMiBkYXRhIHNldApgYGB7ciBjcmVhdGUtZGVzZXEyLWRhdGEtc2V0LCBjYWNoZT1UUlVFfQpkZHNfQXB1bF9zUk5BIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gQXB1bF9jb3VudHNfc1JOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdGltZS5wb2ludCArIGNvbG9ueS5pZCkKZGRzX0FwdWxfc1JOQQpgYGAKYGBge3J9CmRkc19BcHVsX3NSTkEkdGltZS5wb2ludCA8LSBmYWN0b3IoZGRzX0FwdWxfc1JOQSR0aW1lLnBvaW50LCBsZXZlbHMgPSBjKCJUUDEiLCJUUDIiLCAiVFAzIiwgIlRQNCIpKQoKZGRzX0FwdWxfc1JOQSA8LSBERVNlcShkZHNfQXB1bF9zUk5BKQpgYGAKCiMjIFBhaXJ3aXNlIHJlc3VsdHMgdGFibGVzCgpgYGB7ciBkZXNlcTItcGFpcndpc2UtcmVzdWx0cy10YWJsZXN9CiMgRGVmaW5lIHRoZSBvdXRwdXQgZGlyZWN0b3J5IHBhdGgKb3V0cHV0X2RpciA8LSAiLi4vb3V0cHV0LzAzLjEwLUQtQXB1bC1zUk5Bc2VxLWV4cHJlc3Npb24tREVTZXEyLyIKCiMgU2V0IGRlc2lyZWQgZmFsc2UgZGlzY292ZXJ5IHJhdGUgdGhyZXNob2xkIChpLmUuIGFkanVzdGVkIHAtdmFsdWUsIHBhZGopCmZkciA8LSAwLjA1CgojIFNldCBsb2cyIGZvbGQgY2hhbmdlIHRocmVzaG9sZCAoYSB2YWx1ZSBvZiAnMScgaXMgZXF1YWwgdG8gYSBmb2xkIGNoYW5nZSBvZiAnMicpCmxvZzJmYyA8LSAxCgpzUk5BX3RwMS52LnRwMi5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMSIsIlRQMiIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQpzUk5BX3RwMS52LnRwMy5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMSIsIlRQMyIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQpzUk5BX3RwMS52LnRwNC5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMSIsIlRQNCIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQpzUk5BX3RwMi52LnRwMy5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMiIsIlRQMyIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQpzUk5BX3RwMi52LnRwNC5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMiIsIlRQNCIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQpzUk5BX3RwMy52LnRwNC5yZXN1bHRzIDwtIHJlc3VsdHMoZGRzX0FwdWxfc1JOQSwgY29udHJhc3Q9YygidGltZS5wb2ludCIsIlRQMyIsIlRQNCIpLCBhbHBoYSA9IGZkciwgbGZjVGhyZXNob2xkID0gbG9nMmZjKQoKc1JOQV90cDIudi50cDQucmVzdWx0cwoKc3VtbWFyeShzUk5BX3RwMi52LnRwNC5yZXN1bHRzKQoKdGFibGUoc1JOQV90cDIudi50cDQucmVzdWx0cyRwYWRqIDwgMC4wNSkKYGBgCgogV3JpdGUgRERTIHJlc3VsdHMgdGFibGVzIHRvIENTVnMKYGBge3Igd3JpdGUtZGRzLXJlc3VsdHMtY3N2fQojIENyZWF0ZSBhIG5hbWVkIGxpc3Qgb2YgdGhlIGRhdGEgZnJhbWVzCnJlc3VsdHNfbGlzdCA8LSBsaXN0KAogIHNSTkFfdHAxLnYudHAyLnJlc3VsdHMgPSBzUk5BX3RwMS52LnRwMi5yZXN1bHRzLAogIHNSTkFfdHAxLnYudHAzLnJlc3VsdHMgPSBzUk5BX3RwMS52LnRwMy5yZXN1bHRzLAogIHNSTkFfdHAxLnYudHA0LnJlc3VsdHMgPSBzUk5BX3RwMS52LnRwNC5yZXN1bHRzLAogIHNSTkFfdHAyLnYudHAzLnJlc3VsdHMgPSBzUk5BX3RwMi52LnRwMy5yZXN1bHRzLAogIHNSTkFfdHAyLnYudHA0LnJlc3VsdHMgPSBzUk5BX3RwMi52LnRwNC5yZXN1bHRzLAogIHNSTkFfdHAzLnYudHA0LnJlc3VsdHMgPSBzUk5BX3RwMy52LnRwNC5yZXN1bHRzCikKCiMgTG9vcCB0aHJvdWdoIHRoZSBsaXN0IGFuZCB3cml0ZSBlYWNoIGRhdGEgZnJhbWUgdG8gYSBDU1YgZmlsZSBpbiB0aGUgc3BlY2lmaWVkIGRpcmVjdG9yeQpmb3IgKGRmX25hbWUgaW4gbmFtZXMocmVzdWx0c19saXN0KSkgewogIHdyaXRlLmNzdihyZXN1bHRzX2xpc3RbW2RmX25hbWVdXSwgZmlsZSA9IHBhc3RlMChvdXRwdXRfZGlyLCBkZl9uYW1lLCAiLnRhYmxlLmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKfQpgYGAKCiMjIE5vcm1hbGl6YXRpb25zCgpJdCdzIHdvcnRoIG5vdGluZyBoZXJlIHRoYXQgSSdtIGFjdHVhbGx5IGdvaW5nIHRvIGJlIGRvaW5nIHR3byBkaWZmZXJlbnQgdHlwZXMgb2YgdHJhbnNmb3JtYXRpb24gb24gdGhlIGNvdW50cyBkYXRhLCB3aGljaCBzZXJ2ZSBkaWZmZXJlbnQgcHVycG9zZXMuIAoKLSBGaXJzdCBpcyAqKm5vcm1hbGl6aW5nKiogdGhlIHRyYW5zY3JpcHQgY291bnRzLCB3aGljaCBhZGp1c3RzIGZvciBkaWZmZXJlbmNlcyBpbiBsaWJyYXJ5IHNpemUgb3Igc2VxdWVuY2luZyBkZXB0aCwgYnV0IHJldGFpbnMgY291bnQtbGlrZSBwcm9wZXJ0aWVzLiBOb3JtYWxpemVkIGNvdW50cyBhcmUgbW9zdCB1c2VmdWwgZm9yIHRoaW5ncyBsaWtlIHZpc3VhbGl6aW5nIGV4cHJlc3Npb24gbGV2ZWxzIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcy4KCi0gU2Vjb25kIGlzICoqdmFyaWFuY2Ugc3RhYmlsaXppbmcqKiB0aGUgY291bnRzIGRhdGEsIHdoaWNoIGFpbXMgdG8gbWFrZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIHRyYW5zZm9ybWVkIGRhdGEgYXBwcm94aW1hdGVseSBpbmRlcGVuZGVudCBvZiB0aGUgbWVhbiwgcmVkdWNpbmcgaGV0ZXJvc2NlZGFzdGljaXR5ICh0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFuY2UgYW5kIG1lYW4pIGFuZCAic21vb3RoaW5nIiBvdXQgdGhlIHZhcmlhbmNlIGF0IGxvdyBjb3VudHMuIE5vdGFibHksIHRoZSB0cmFuc2Zvcm1lZCBkYXRhIGlzICpubyBsb25nZXIgb24gdGhlIG9yaWdpbmFsIGNvdW50IHNjYWxlKi4gVGhlIHRyYW5zZm9ybWF0aW9uIG1ha2VzIHRoZSB2YXJpYW5jZSByb3VnaGx5IGNvbnN0YW50IGFjcm9zcyB0aGUgcmFuZ2Ugb2YgY291bnRzLCB3aGljaCBtYWtlcyBpdCBlYXNpZXIgdG8gaW50ZXJwcmV0IHBhdHRlcm5zIGluIHRoZSBkYXRhIHZpc3VhbGx5LiBWYXJpYW5jZSBzdGFiaWxpemVkIGRhdGEgaXMgbW9zdCB1c2VmdWwgZm9yIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMsIGxpa2UgUENBLCBjbHVzdGVyaW5nLCBhbmQgaGVhdG1hcHMsIGFuZCBpcyBhbHNvIHRoZSB0cmFuc2Zvcm1hdGlvbiB3ZSdsbCB3YW50IHRvIHVzZSBiZWZvcmUgV0dDTkEuCgpgYGB7ciBnZXQtbm9ybWFsaXplZC1zUk5BLWNvdW50cywgY2FjaGU9VFJVRX0KIyBleHRyYWN0IG5vcm1hbGl6ZWQgY291bnRzCiMgKG5vcm1hbGl6YXRpb24gaXMgYXV0b21hdGljYWxseSBwZXJmb3JtZWQgYnkgZGVzZXEyKQpBcHVsX2NvdW50c19zUk5BX25vcm0gPC0gY291bnRzKGRkc19BcHVsX3NSTkEsIG5vcm1hbGl6ZWQ9VFJVRSkgJT4lIGRhdGEuZnJhbWUoKQoKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfc1JOQV9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX2NvdW50c19zUk5BX25vcm1hbGl6ZWQudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSwgcXVvdGUgPSBGQUxTRSkKCgojIHZhcmlhbmNlIHN0YWJpbGl6ZWQgZGF0YQp2c2RfQXB1bF9zUk5BIDwtIHZhcmlhbmNlU3RhYmlsaXppbmdUcmFuc2Zvcm1hdGlvbihkZHNfQXB1bF9zUk5BLCBibGluZD1UUlVFKQp3cG5fdnNkX0FwdWxfc1JOQSA8LSBnZXRWYXJpYW5jZVN0YWJpbGl6ZWREYXRhKGRkc19BcHVsX3NSTkEpCnJ2X3dwbl9BcHVsX3NSTkEgPC0gcm93VmFycyh3cG5fdnNkX0FwdWxfc1JOQSwgdXNlTmFtZXM9VFJVRSkKCkFwdWxfY291bnRzX3NSTkFfdnNkIDwtIGRhdGEuZnJhbWUod3BuX3ZzZF9BcHVsX3NSTkEpCndyaXRlLnRhYmxlKEFwdWxfY291bnRzX3NSTkFfdnNkLCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCgpxNzVfd3BuX0FwdWxfc1JOQSA8LSBxdWFudGlsZShyb3dWYXJzKHdwbl92c2RfQXB1bF9zUk5BLCB1c2VOYW1lcz1UUlVFKSwgLjc1KSAgIyA3NXRoIHF1YW50aWxlIHZhcmlhYmlsaXR5CkFwdWxfY291bnRzX3NSTkFfdnNkX3E3NSA8LSB3cG5fdnNkX0FwdWxfc1JOQVsgcnZfd3BuX0FwdWxfc1JOQSA+IHE3NV93cG5fQXB1bF9zUk5BLCBdICU+JSBkYXRhLmZyYW1lICMgZmlsdGVyIHRvIHJldGFpbiBvbmx5IHRoZSBtb3N0IHZhcmlhYmxlIGdlbmVzCndyaXRlLnRhYmxlKEFwdWxfY291bnRzX3NSTkFfdnNkX3E3NSwgZmlsZSA9ICIuLi9vdXRwdXQvMDMuMTAtRC1BcHVsLXNSTkFzZXEtZXhwcmVzc2lvbi1ERVNlcTIvQXB1bF9jb3VudHNfc1JOQV92YXJpYW5jZXN0YWJpbGl6ZWRfcTc1LnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKCnE5NV93cG5fQXB1bF9zUk5BIDwtIHF1YW50aWxlKHJvd1ZhcnMod3BuX3ZzZF9BcHVsX3NSTkEsIHVzZU5hbWVzPVRSVUUpLCAuOTUpICAjIDk1dGggcXVhbnRpbGUgdmFyaWFiaWxpdHkKQXB1bF9jb3VudHNfc1JOQV92c2RfcTk1IDwtIHdwbl92c2RfQXB1bF9zUk5BWyBydl93cG5fQXB1bF9zUk5BID4gcTk1X3dwbl9BcHVsX3NSTkEsIF0gJT4lIGRhdGEuZnJhbWUgIyBmaWx0ZXIgdG8gcmV0YWluIG9ubHkgdGhlIG1vc3QgdmFyaWFibGUgZ2VuZXMKd3JpdGUudGFibGUoQXB1bF9jb3VudHNfc1JOQV92c2RfcTk1LCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX2NvdW50c19zUk5BX3ZhcmlhbmNlc3RhYmlsaXplZF9xOTUudHh0Iiwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gVFJVRSxxdW90ZSA9IEZBTFNFKQpgYGAKCiMjIFBsb3Qgbm9ybWFsaXplZCBkYXRhCgpgYGB7ciBwbG90LW5vcm1hbGl6ZWQtc1JOQX0KQXB1bF9jb3VudHNfc1JOQV9ub3JtX2xvbmcgPC0gQXB1bF9jb3VudHNfc1JOQV9ub3JtICU+JQogIG11dGF0ZSgKICAgIEdlbmVfaWQgPSByb3cubmFtZXMoQXB1bF9jb3VudHNfc1JOQV9ub3JtKQogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1HZW5lX2lkKQoKQXB1bF9jb3VudHNfc1JOQV9ub3JtX2xvbmcgJT4lCiAgZ2dwbG90KC4sIGFlcyh4ID0gbmFtZSwgeSA9IHZhbHVlKSkgKwogIGdlb21fdmlvbGluKCkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCggYW5nbGUgPSA5MCkKICApICsKICB5bGltKDAsIE5BKSArCiAgbGFicygKICAgIHRpdGxlID0gIk5vcm1hbGl6ZWQgRXhwcmVzc2lvbiIsCiAgICB4ID0gIlNhbXBsZSIsCiAgICB5ID0gIk5vcm1hbGl6ZWQgY291bnRzIgogICkKYGBgCgoKIyMgUGxvdCB2YXJpYW5jZSBzdGFiaWxpemVkIGRhdGEKCmBgYHtyIHBsb3QtdnNkLXNSTkF9CkFwdWxfY291bnRzX3NSTkFfdnNkX2xvbmcgPC0gQXB1bF9jb3VudHNfc1JOQV92c2QgJT4lCiAgbXV0YXRlKAogICAgR2VuZV9pZCA9IHJvdy5uYW1lcyhBcHVsX2NvdW50c19zUk5BX3ZzZCkKICApICU+JQogIHBpdm90X2xvbmdlcigtR2VuZV9pZCkKCkFwdWxfY291bnRzX3NSTkFfdnNkX2xvbmcgJT4lCiAgZ2dwbG90KC4sIGFlcyh4ID0gbmFtZSwgeSA9IHZhbHVlKSkgKwogIGdlb21fdmlvbGluKCkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCggYW5nbGUgPSA5MCkKICApICsKICB5bGltKDAsIE5BKSArCiAgbGFicygKICAgIHRpdGxlID0gIlZhcmlhbmNlIFN0YWJpbGl6ZWQgRXhwcmVzc2lvbiIsCiAgICB4ID0gIlNhbXBsZSIsCiAgICB5ID0gIlZhcmlhbmNlIHN0YWJpbGl6ZWQgZGF0YSIKICApCmBgYAoKIyMgTm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBub3JtLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19ub3JtX21lbHRlZCA8LSBtZWx0KEFwdWxfY291bnRzX3NSTkFfbm9ybSwgdmFyaWFibGUubmFtZSA9ICJzYW1wbGUiLCB2YWx1ZS5uYW1lID0gImNvdW50cyIpCgojIFBsb3QgdGhlIGV4cHJlc3Npb24gbGV2ZWwgaGlzdG9ncmFtcyBmb3IgZWFjaCBzYW1wbGUKZ2dwbG90KEFwdWxfY291bnRzX25vcm1fbWVsdGVkLCBhZXMoeCA9IGNvdW50cykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiIzQwOEVDNiIsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfbG9nMTAoKSArICAjIE9wdGlvbmFsOiBMb2ctdHJhbnNmb3JtIHRoZSB4LWF4aXMgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uCiAgZmFjZXRfd3JhcCh+c2FtcGxlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnModGl0bGUgPSAiR2VuZSBFeHByZXNzaW9uIExldmVsIEhpc3RvZ3JhbSBmb3IgRWFjaCBTYW1wbGUiLAogICAgICAgeCA9ICJFeHByZXNzaW9uIExldmVsIChDb3VudHMpIiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIE5vcm1hbGl6ZWQgdHJhbnNjcmlwdCBjb3VudHMKCkNoZWNrIHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgaW4gZWFjaCBzYW1wbGUgLS0gbm93IHRoYXQgd2UndmUgbm9ybWFsaXplZCB0aGUgZGF0YSB0aGVzZSB0b3RhbHMgc2hvdWxkIGJlIHNpbWlsYXIKYGBge3Igbm9ybS10cmFuc2NyaXB0LWNvdW50cy1wbG90fQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQp0b3RhbF90cmFuc2NyaXB0c19ub3JtIDwtIGNvbFN1bXMoQXB1bF9jb3VudHNfc1JOQV9ub3JtKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZwp0b3RhbF90cmFuc2NyaXB0c19ub3JtX2RmIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gbmFtZXModG90YWxfdHJhbnNjcmlwdHNfbm9ybSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxzID0gdG90YWxfdHJhbnNjcmlwdHNfbm9ybSkKCiMgUGxvdCB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGZvciBlYWNoIHNhbXBsZQpnZ3Bsb3QodG90YWxfdHJhbnNjcmlwdHNfbm9ybV9kZiwgYWVzKHggPSByZW9yZGVyKHNhbXBsZSwgdG90YWxzKSwgeSA9IHRvdGFscykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDA4RUM2IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFscyksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIFRyYW5zY3JpcHRzIHBlciBTYW1wbGUiLAogICAgICAgeCA9ICJTYW1wbGUiLAogICAgICAgeSA9ICJUb3RhbCBUcmFuc2NyaXB0cyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGF0ZSB4LWF4aXMgbGFiZWxzIGZvciByZWFkYWJpbGl0eQpgYGAKCiMjIFBDQSBvZiB2YXJpYW5jZSBzdGFiaWxpemVkIGRhdGEKCmBgYHtyIFBDQX0KcGxvdFBDQSh2c2RfQXB1bF9zUk5BLCBpbnRncm91cD0idGltZS5wb2ludCIpCgpwbG90UENBKHZzZF9BcHVsX3NSTkEsIGludGdyb3VwPSJjb2xvbnkuaWQiKQpgYGAKU2FtcGxlcyBhcmUgc3Ryb25nbHkgY2x1c3RlcmluZyBieSBjb2xvbnkuIEludGVyZXN0aW5nbHkgdGltZSBwb2ludCBkb2Vzbid0IGFwcGVhciB0byBpbmZsdWVuY2UgY2x1c3RlcmluZy4KCiMjIFNhbXBsZSBjbHVzdGVyaW5nCgpgYGB7ciBzYW1wbGUtY2x1c3RlcmluZ30Kc2FtcGxlX2Rpc3RzIDwtIGRpc3QodChhc3NheSh2c2RfQXB1bF9zUk5BKSkpCnBoZWF0bWFwKGFzLm1hdHJpeChzYW1wbGVfZGlzdHMpLCAKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImV1Y2xpZGVhbiIsIAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgIG1haW49IlNhbXBsZSBDbHVzdGVyaW5nIikKYGBgClNhbXBsZXMgYXJlIHN0cm9uZ2x5IGNsdXN0ZXJpbmcgYnkgY29sb255LgoKIyMgSGVhdG1hcHMKCk9mIG1vc3QgdmFyaWFibGUgdmFyaWFuY2Ugc3RhYmlsaXplZCBzUk5BIHRyYW5zY3JpcHRzCgpgYGB7ciBoZWF0bXBhc30KIyA3NXRoIHF1YW50aWxlCmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCnBoZWF0bWFwKEFwdWxfY291bnRzX3NSTkFfdnNkX3E3NSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywKICAgICAgICAgc2NhbGU9InJvdyIpCgojIDk1dGggcXVhbnRpbGUKcGhlYXRtYXAoQXB1bF9jb3VudHNfc1JOQV92c2RfcTk1LCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLAogICAgICAgICBzY2FsZT0icm93IikKYGBgCgojIE5vcm1hbGl6ZWQgbWlSTkEgY291bnRzCgojIyBJc29sYXRlIG5vcm1hbGl6ZWQvdnNkIG1pUk5BCmBgYHtyIG1pUk5BLW5vcm1hbGl6ZWQtbWlSTkF9CgpBcHVsX2NvdW50c19zUk5BX25vcm0kTmFtZSA8LSByb3duYW1lcyhBcHVsX2NvdW50c19zUk5BX25vcm0pCkFwdWxfY291bnRzX3NSTkFfdnNkJE5hbWUgPC0gcm93bmFtZXMoQXB1bF9jb3VudHNfc1JOQV92c2QpCgpBcHVsX2NvdW50c19taVJOQV9uYW1lc2RmIDwtIGRhdGEuZnJhbWUoTmFtZSA9IHJvd25hbWVzKEFwdWxfY291bnRzX21pUk5BKSkgCgpBcHVsX2NvdW50c19taVJOQV9ub3JtIDwtIGxlZnRfam9pbihBcHVsX2NvdW50c19taVJOQV9uYW1lc2RmLCBBcHVsX2NvdW50c19zUk5BX25vcm0sIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQp3cml0ZS50YWJsZShBcHVsX2NvdW50c19taVJOQV9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX2NvdW50c19taVJOQV9ub3JtYWxpemVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKCkFwdWxfY291bnRzX21pUk5BX3ZzZCA8LSBsZWZ0X2pvaW4oQXB1bF9jb3VudHNfbWlSTkFfbmFtZXNkZiwgQXB1bF9jb3VudHNfc1JOQV92c2QsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQp3cml0ZS50YWJsZShBcHVsX2NvdW50c19taVJOQV92c2QsIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEwLUQtQXB1bC1zUk5Bc2VxLWV4cHJlc3Npb24tREVTZXEyL0FwdWxfY291bnRzX21pUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgTm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBtaVJOQS1ub3JtLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCA8LSBtZWx0KEFwdWxfY291bnRzX21pUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19taVJOQV9ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIG1pUk5BLW5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfbWlSTkFfbm9ybSA8LSBjb2xTdW1zKEFwdWxfY291bnRzX21pUk5BX25vcm0pCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX21pUk5BX25vcm1fZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19taVJOQV9ub3JtX2RmLCBhZXMoeCA9IHJlb3JkZXIoc2FtcGxlLCB0b3RhbHMpLCB0b3RhbHMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzQwOEVDNiIsIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB0b3RhbHMpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBtaVJOQSBUcmFuc2NyaXB0cyBwZXIgU2FtcGxlIiwKICAgICAgIHggPSAiU2FtcGxlIiwKICAgICAgIHkgPSAiVG90YWwgVHJhbnNjcmlwdHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgcmVhZGFiaWxpdHkKYGBgCiMjIFBDQSBvZiB2YXJpYW5jZSBzdGFiaWxpemVkIG1pUk5BcwoKTm90ZSB0aGF0IEkgaGFkIHRvIGNvbnZlcnQgdGhlIGNvdW50cyB0byBhIGRhdGEgZnJhbWUgKGluc3RlYWQgb2YgYSBERVNlcVRyYW5zZm9ybSBvYmplY3QpIHRvIHNlbGVjdCBvbmx5IG1pUk5Bcywgc28gSSBjYW4ndCB1c2UgdGhlIHBsb3RQQ0EoKSBmdW5jdGlvbi4KYGBge3IgbWlSTkEtY2x1c3RlcmluZy12c2R9CiMgUGVyZm9ybSBQQ0EKcGNhX3JlcyA8LSBwcmNvbXAodChhcy5tYXRyaXgoQXB1bF9jb3VudHNfbWlSTkFfdnNkKSkpCgojIENhbGN1bGF0ZSBwZXJjZW50IHZhcmlhbmNlIGV4cGxhaW5lZApwZXJjZW50VmFyIDwtIHJvdW5kKDEwMCAqIChwY2FfcmVzJHNkZXZeMiAvIHN1bShwY2FfcmVzJHNkZXZeMikpKQoKIyMgQ29sb3IgYnkgY29sb255IElEICMjCiMgQ29udmVydCBQQ0EgcmVzdWx0cyB0byBkYXRhIGZyYW1lCnBjYV9kZiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXMkeCkKcGNhX2RmJGNvbG9ueS5pZCA8LSBkZHNfQXB1bF9zUk5BJGNvbG9ueS5pZAoKIyBDcmVhdGUgUENBIHBsb3Qgd2l0aCBwZXJjZW50IHZhcmlhbmNlCmdncGxvdChwY2FfZGYsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGNvbG9ueS5pZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgbGFicygKICAgIHggPSBwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgIHkgPSBwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUgdmFyaWFuY2UiKSwKICAgIHRpdGxlID0gIlBDQSBvZiBWU0QgbWlSTkEgQ291bnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKIyMgQ29sb3IgYnkgY29sb255IElEICMjCiMgQ29udmVydCBQQ0EgcmVzdWx0cyB0byBkYXRhIGZyYW1lCnBjYV9kZiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXMkeCkKcGNhX2RmJHRpbWUucG9pbnQgPC0gZGRzX0FwdWxfc1JOQSR0aW1lLnBvaW50CgojIENyZWF0ZSBQQ0EgcGxvdCB3aXRoIHBlcmNlbnQgdmFyaWFuY2UKZ2dwbG90KHBjYV9kZiwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gdGltZS5wb2ludCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgbGFicygKICAgIHggPSBwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgIHkgPSBwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUgdmFyaWFuY2UiKSwKICAgIHRpdGxlID0gIlBDQSBvZiBWU0QgbWlSTkEgQ291bnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCkludGVyZXN0aW5nISBXaGVuIGNvbnNpZGVyaW5nIGFsbCBzUk5BcywgdGhleSBzdHJvbmdseSBjbHVzdGVyZWQgYnkgY29sb255IGFuZCBub3QgdGltZSBwb2ludC4gSG93ZXZlciwgbWlSTkFzIGFsb25lIHNob3cgY2xlYXIgY2x1c3RlcmluZyBieSB0aW1lIHBvaW50ICh0aG91Z2ggc29tZSBpbmZsdWVuY2Ugb2YgY29sb255IGlzIHN0aWxsIGFwcGFyZW50KS4KCiMjIFNhbXBsZSBjbHVzdGVyaW5nCgpgYGB7ciBtaVJOQS1zYW1wbGUtY2x1c3RlcmluZ30KCiMgQ2FsY3VsYXRlIHRoZSBFdWNsaWRlYW4gZGlzdGFuY2UgbWF0cml4CnNhbXBsZV9kaXN0cyA8LSBkaXN0KHQoQXB1bF9jb3VudHNfbWlSTkFfdnNkKSkKCiMgQ3JlYXRlIHRoZSBoZWF0bWFwCnBoZWF0bWFwKAogIGFzLm1hdHJpeChzYW1wbGVfZGlzdHMpLCAKICBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwgCiAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImV1Y2xpZGVhbiIsIAogIG1haW4gPSAiU2FtcGxlIENsdXN0ZXJpbmciCikKYGBgCgoKIyMgSGVhdG1hcAoKT2YgYWxsIG1pUk5BcwoKYGBge3IgbWlSTkEtaGVhdG1hcHMtdnNkfQpoZWF0X2NvbG9ycyA8LSByZXYoYnJld2VyLnBhbCgxMiwgIlJkWWxCdSIpKQoKcGhlYXRtYXAoYXMubWF0cml4KEFwdWxfY291bnRzX21pUk5BX3ZzZFthcHBseShBcHVsX2NvdW50c19taVJOQV92c2QsIDEsIHZhcikgPiAwLCBdKSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsCiAgICAgICAgIHNjYWxlPSJyb3ciKQojIAojIHRvcF8yMF9jb3VudHNfYWxsIDwtIG9yZGVyKHJvd01lYW5zKGNvdW50cyhkZHMsbm9ybWFsaXplZD1UUlVFKSksCiMgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmc9VFJVRSlbMToyMDBdCiMgCiMgdGltZXBvaW50X2Fubm90YXRpb24gPSBjb2xEYXRhKGRkcykgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgc2VsZWN0KHRpbWUucG9pbnQpCiMgCiMgCiMgcGhlYXRtYXAoYXNzYXkodnNkKVt0b3BfMjBfY291bnRzX2FsbCxdLCAKIyAgICAgICAgICBjbHVzdGVyX3Jvd3M9RkFMU0UsIAojICAgICAgICAgIHNob3dfcm93bmFtZXM9RkFMU0UsCiMgICAgICAgICAgY2x1c3Rlcl9jb2xzPVRSVUUsIAojICAgICAgICAgIGFubm90YXRpb25fY29sID0gdGltZXBvaW50X2Fubm90YXRpb24pCgpgYGAKCgoKYGBge3J9CiMgUGVyZm9ybSBjbHVzdGVyaW5nIGJhc2VkIG9uIG5vcm1hbGl6ZWQgZXhwcmVzc2lvbgpjbHVzdGVyaW5nIDwtIHBoZWF0bWFwKGFzLm1hdHJpeChBcHVsX2NvdW50c19taVJOQV9ub3JtKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNpbGVudCA9IFRSVUUpICAjIFNhdmUgY2x1c3RlcmluZyB3aXRob3V0IHBsb3R0aW5nCgojIENvbnZlcnQgbm9ybWFsaXplZCBjb3VudHMgdG8gYmluYXJ5IChwcmVzZW5jZS9hYnNlbmNlKQpiaW5hcnlfY291bnRzIDwtIEFwdWxfY291bnRzX21pUk5BX25vcm0gPiAwCmJpbmFyeV9jb3VudHMgPC0gYXMubWF0cml4KGJpbmFyeV9jb3VudHMpICogMSAgIyBDb252ZXJ0IGxvZ2ljYWwgdG8gbnVtZXJpYyAoMS8wKQoKIyBHZW5lcmF0ZSBoZWF0bWFwIHdpdGggYmluYXJ5IHZhbHVlcyB1c2luZyB0aGUgcHJlY29tcHV0ZWQgY2x1c3RlcmluZwpwaGVhdG1hcChiaW5hcnlfY291bnRzLCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gY2x1c3RlcmluZyR0cmVlX3JvdywgICMgVXNlIHJvdyBjbHVzdGVyaW5nIGZyb20gbm9ybWFsaXplZCBkYXRhCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IGNsdXN0ZXJpbmckdHJlZV9jb2wsICAjIFVzZSBjb2x1bW4gY2x1c3RlcmluZyBmcm9tIG5vcm1hbGl6ZWQgZGF0YQogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIGNvbG9yID0gYygid2hpdGUiLCAiYmxhY2siKSkgICMgV2hpdGUgZm9yIDAgKGFic2VuY2UpLCBibGFjayBmb3IgMSAocHJlc2VuY2UpCgpgYGAKCkl0IGxvb2tzIGxpa2UsIG9mIHRoZSA1MSB0b3RhbCBtaVJOQXMgaWRlbnRpZmllZCwgbW9zdCBhcmUgY29uc2lzdGVudGx5IHByZXNlbnQgaW4gYWxsIEEucHVsY2hyYSBjb2xvbmllcyBhbmQgdGltZSBwb2ludHMuIEZvciAxMC0xNSBvZiB0aGUgbWlSTkFzLCBwcmVzZW5jZS9hYnNlbmNlIGlzIG1vcmUgdmFyaWFibGUgYWNjcm9zcyBjb2xvbmllcyBhbmQgdGltZXBvaW50cy4KCgoKCmBgYHtyfQpyZXN1bHRzX2RmIDwtIGFzLmRhdGEuZnJhbWUoc1JOQV90cDMudi50cDQucmVzdWx0cykKcmVzdWx0c19kZiROYW1lIDwtIHJvd25hbWVzKHJlc3VsdHNfZGYpCgojIEFzc3VtaW5nIHlvdXIgbWV0YWRhdGEgZnJhbWUgYWxzbyBoYXMgYSAnTmFtZScgY29sdW1uCiMgUGVyZm9ybSB0aGUgbGVmdCBqb2luIHRvIHNlbGVjdCBvbmx5IHRoZSBnZW5lcyBsaXN0ZWQgaW4gbWV0YWRhdGEKZmlsdGVyZWRfcmVzdWx0cyA8LSBkcGx5cjo6bGVmdF9qb2luKEFwdWxfY291bnRzX21pUk5BX25hbWVzZGYsIHJlc3VsdHNfZGYsIGJ5ID0gIk5hbWUiKQoKZmlsdGVyKGZpbHRlcmVkX3Jlc3VsdHMsIHBhZGogPCAwLjA1KQpgYGAKCgoKCgojIE5vcm1hbGl6ZWQgc2lSTkEgY291bnRzCgojIyBJc29sYXRlIG5vcm1hbGl6ZWQvdnNkIHNpUk5BCmBgYHtyIHNpUk5BLW5vcm1hbGl6ZWQtc2lSTkF9CgpBcHVsX2NvdW50c19zUk5BX25vcm0kTmFtZSA8LSByb3duYW1lcyhBcHVsX2NvdW50c19zUk5BX25vcm0pCkFwdWxfY291bnRzX3NSTkFfdnNkJE5hbWUgPC0gcm93bmFtZXMoQXB1bF9jb3VudHNfc1JOQV92c2QpCgpBcHVsX2NvdW50c19zaVJOQV9uYW1lc2RmIDwtIGRhdGEuZnJhbWUoTmFtZSA9IHJvd25hbWVzKEFwdWxfY291bnRzX3NpUk5BKSkgCgpBcHVsX2NvdW50c19zaVJOQV9ub3JtIDwtIGxlZnRfam9pbihBcHVsX2NvdW50c19zaVJOQV9uYW1lc2RmLCBBcHVsX2NvdW50c19zUk5BX25vcm0sIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zaVJOQV9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wMy4xMC1ELUFwdWwtc1JOQXNlcS1leHByZXNzaW9uLURFU2VxMi9BcHVsX2NvdW50c19zaVJOQV9ub3JtYWxpemVkLnR4dCIsIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IFRSVUUscXVvdGUgPSBGQUxTRSkKCkFwdWxfY291bnRzX3NpUk5BX3ZzZCA8LSBsZWZ0X2pvaW4oQXB1bF9jb3VudHNfc2lSTkFfbmFtZXNkZiwgQXB1bF9jb3VudHNfc1JOQV92c2QsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIk5hbWUiKQp3cml0ZS50YWJsZShBcHVsX2NvdW50c19zaVJOQV92c2QsIGZpbGUgPSAiLi4vb3V0cHV0LzAzLjEwLUQtQXB1bC1zUk5Bc2VxLWV4cHJlc3Npb24tREVTZXEyL0FwdWxfY291bnRzX3NpUk5BX3ZhcmlhbmNlc3RhYmlsaXplZC50eHQiLCBzZXAgPSAiXHQiLCByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBUUlVFLHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgTm9ybWFsaXplZCBleHByZXNzaW9uIGxldmVscwoKUGxvdCBoaXN0b2dyYW1zIG9mIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbGV2ZWxzIGluIGVhY2ggc2FtcGxlCgpgYGB7ciBzaVJOQS1ub3JtLWV4cHJlc3Npb24tbGV2ZWwtaGlzdG9ncmFtc30KIyBNZWx0IHRoZSBjb3VudCBtYXRyaXggaW50byBsb25nIGZvcm1hdApBcHVsX2NvdW50c19zaVJOQV9ub3JtX21lbHRlZCA8LSBtZWx0KEFwdWxfY291bnRzX3NpUk5BX25vcm0sIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlIiwgdmFsdWUubmFtZSA9ICJjb3VudHMiKQoKIyBQbG90IHRoZSBleHByZXNzaW9uIGxldmVsIGhpc3RvZ3JhbXMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdChBcHVsX2NvdW50c19zaVJOQV9ub3JtX21lbHRlZCwgYWVzKHggPSBjb3VudHMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2xvZzEwKCkgKyAgIyBPcHRpb25hbDogTG9nLXRyYW5zZm9ybSB0aGUgeC1heGlzIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgRXhwcmVzc2lvbiBMZXZlbCBIaXN0b2dyYW0gZm9yIEVhY2ggU2FtcGxlIiwKICAgICAgIHggPSAiRXhwcmVzc2lvbiBMZXZlbCAoQ291bnRzKSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBOb3JtYWxpemVkIHRyYW5zY3JpcHQgY291bnRzCgpDaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHRyYW5zY3JpcHRzIGluIGVhY2ggc2FtcGxlIC0tIG5vdyB0aGF0IHdlJ3ZlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgdGhlc2UgdG90YWxzIHNob3VsZCBiZSBzaW1pbGFyCmBgYHtyIHNpUk5BLW5vcm0tdHJhbnNjcmlwdC1jb3VudHMtcGxvdH0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiB0cmFuc2NyaXB0cyBmb3IgZWFjaCBzYW1wbGUKdG90YWxfdHJhbnNjcmlwdHNfc2lSTkFfbm9ybSA8LSBjb2xTdW1zKEFwdWxfY291bnRzX3NpUk5BX25vcm0pCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nCnRvdGFsX3RyYW5zY3JpcHRzX3NpUk5BX25vcm1fZGYgPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBuYW1lcyh0b3RhbF90cmFuc2NyaXB0c19zaVJOQV9ub3JtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbHMgPSB0b3RhbF90cmFuc2NyaXB0c19zaVJOQV9ub3JtKQoKIyBQbG90IHRoZSB0b3RhbCBudW1iZXIgb2YgdHJhbnNjcmlwdHMgZm9yIGVhY2ggc2FtcGxlCmdncGxvdCh0b3RhbF90cmFuc2NyaXB0c19zaVJOQV9ub3JtX2RmLCBhZXMoeCA9IHJlb3JkZXIoc2FtcGxlLCB0b3RhbHMpLCB5ID0gdG90YWxzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiM0MDhFQzYiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWxzKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2Ygc2lSTkEgVHJhbnNjcmlwdHMgcGVyIFNhbXBsZSIsCiAgICAgICB4ID0gIlNhbXBsZSIsCiAgICAgICB5ID0gIlRvdGFsIFRyYW5zY3JpcHRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXRlIHgtYXhpcyBsYWJlbHMgZm9yIHJlYWRhYmlsaXR5CmBgYAoKIyMgSGVhdG1hcAoKT2YgYWxsIHNpUk5BcwoKYGBge3Igc2lSTkEtaGVhdG1hcHMtdnNkfQpoZWF0X2NvbG9ycyA8LSByZXYoYnJld2VyLnBhbCgxMiwgIlJkWWxCdSIpKQpwaGVhdG1hcChhcy5tYXRyaXgoQXB1bF9jb3VudHNfc2lSTkFfdnNkW2FwcGx5KEFwdWxfY291bnRzX3NpUk5BX3ZzZCwgMSwgdmFyKSA+IDAsIF0pLCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLAogICAgICAgICBzY2FsZT0icm93IikKCmBgYAoKCgo=