1 Overview

batch condition media treatment induced exp_7
SK082 1 SCFM-DMSO SCFM DMSO no control
SK083 2 SCFM-DMSO SCFM DMSO no control
SK084 3 SCFM-DMSO SCFM DMSO no control
SK085 1 SCFM-IPTG SCFM DMSO yes treatment
SK086 2 SCFM-IPTG SCFM DMSO yes treatment
SK087 3 SCFM-IPTG SCFM DMSO yes treatment

2 Project variables

##       batch condition media treatment induced     exp_7
## SK082     1 SCFM-DMSO  SCFM      DMSO      no   control
## SK083     2 SCFM-DMSO  SCFM      DMSO      no   control
## SK084     3 SCFM-DMSO  SCFM      DMSO      no   control
## SK085     1 SCFM-IPTG  SCFM      DMSO     yes treatment
## SK086     2 SCFM-IPTG  SCFM      DMSO     yes treatment
## SK087     3 SCFM-IPTG  SCFM      DMSO     yes treatment
## [1] "The control is: SCFM-DMSO"
## [1] "The treatment is: SCFM-IPTG"
# Load raw count data
rawcounts <- read.csv("../../raw-data/htseq_SK_unfiltered_reverse_strand_count.csv", 
                      row.names = 1, header = TRUE)

# Append a prefix to the batch and run columns to turn to character class
metadata[["batch"]] <- paste0("b", metadata[["batch"]])
metadata[["run"]] <- paste0("r", metadata[["run"]])

# Subset the rawcounts dataframe to only include samples that are present in experiment
samples <- rownames(metadata)
rawcounts <- select(rawcounts, all_of(samples))

# Ensure that the order of samples in metadata matches the order of columns in rawcounts
all(rownames(metadata) == colnames(rawcounts))  # Should return TRUE if order is correct
## [1] TRUE
# Define the design formula for DESeq2, including main condition and batch effect
design_formula <- ~ exp_7 + batch

# Create DESeq2 dataset object from the filtered count matrix and metadata
dds <- DESeqDataSetFromMatrix(
  countData = rawcounts,
  colData = metadata,
  design = design_formula
)
## Warning in DESeqDataSet(se, design = design, ignoreRank): some variables in
## design formula are characters, converting to factors

3 Library size per sample

# Sum up the counts for each sample
rawcounts_sums <- colSums(rawcounts)

# Turn it into a data frame
data <- data.frame(
  Category = names(rawcounts_sums),
  Count = as.numeric(rawcounts_sums)
)

# Make sure sample order is consistent
data <- data %>%
  mutate(Category = factor(Category, levels = sort(unique(Category))))

# Plot bar chart of library sizes
p <- ggplot(data, aes(x = Category, y = Count, fill = Category)) +
  geom_bar(stat = "identity") +
  # coord_flip() # flip if too many samples to read labels easily
  labs(y = "Library size (M)", x = NULL) +  # remove x label, rename y axis
  # scale_fill_brewer(palette = "Dark2") +  # optional color palette
  scale_y_continuous(
    labels = scales::label_number(scale = 1e-6),  # show counts in millions
    limits = c(0, (max(data$Count) + 1e6))        # add a bit of space on top
  ) +
  theme(
    panel.grid = element_blank(),
    panel.background = element_blank(),
    axis.text = element_text(size = text.size, angle = 45, hjust = 1),  # slant labels
    axis.title = element_text(size = axis.text.size),
    legend.text = element_text(size = text.size),
    legend.title = element_text(size = axis.text.size),
    panel.border = element_rect(fill = NA),
    legend.position = "none",  # no legend needed since each bar is a different sample
    axis.ticks = element_line(linewidth = 0.2),
    legend.key = element_blank()
  )

# Show the plot
p

# Save the plot as a PDF with today’s date and project name
ggsave(paste0(Sys.Date(), "_library_size_", exp, "_", treatment,".vs.", control, ".pdf"), device = "pdf")
## Saving 7 x 5 in image

4 Expression distribution

# Stack rawcounts into single vector 
dat <- stack(rawcounts)

# Format expression distribution plot with the expression level and density 
expression_dist <- ggplot(dat, aes(x = log2(values+1),  fill=ind, label = ind )) + 
  geom_density(alpha = 0.5, position = "identity") + 
  ylab("Density") + 
  geom_textdensity(hjust = "ymax", vjust = 0,
           text_only = TRUE, text_smoothing = 20) + 
    theme(panel.grid = element_blank(),
        panel.background = element_blank(),
        axis.text = element_text(size = text.size),
        axis.title = element_text(size = axis.text.size),
        legend.text = element_text(size = text.size),
        legend.title = element_text(size = axis.text.size),
        panel.border = element_rect(fill = NA),
        legend.position = "none",
        axis.ticks = element_line(linewidth = 0.2),
        legend.key = element_blank()) +
  coord_cartesian(xlim = c(0, 15))

expression_dist

#save figure
cairo_pdf(paste0(Sys.Date(), "_expression_dist_", exp, "_", treatment, ".vs.", control, ".pdf"))
expression_dist
dev.off() 
## quartz_off_screen 
##                 2

5 Non-zero genes observed

# Prepare data by getting library sizes and non-zero counts
x <- colSums(rawcounts)
y <- colSums(rawcounts != 0) 
df <- data.frame(x,y)
df$ind <- rownames(df)

# Calculate axis limits
x_min <- min(df$x)
x_max <- max(df$x)
y_min <- min(df$y)
y_max <- max(df$y)

# Non-zero plot
nonzero <- ggplot(data = df, aes(x = x, y = y, color = ind, label = ind)) +
  geom_point(size = 3) +
  geom_text(hjust = -0.1, vjust = -0.1, color = "black", size = 5) +
  scale_y_continuous(limits=c(y_min, y_max)) + 
  scale_x_continuous(
    limits = c(x_min-1e3, x_max+9e5),
    labels = scales::comma_format(scale = 1e-6,  accuracy = 1)  # Format labels without decimals
  ) +
  xlab("Millions of reads") + ylab("Number of non-zero genes observed") +
  labs(color = "Sample") + 
    theme(panel.grid = element_blank(),
        panel.background = element_blank(),
        axis.text = element_text(size = text.size),
        axis.title = element_text(size = axis.text.size),
        legend.text = element_text(size = text.size),
        legend.title = element_text(size = axis.text.size),
        panel.border = element_rect(fill = NA),
        legend.position = "none",
        axis.ticks = element_line(linewidth = 0.2),
        legend.key = element_blank()) +
  coord_cartesian()

# Show nonzero plot
nonzero

# Save plot

cairo_pdf(paste0(Sys.Date(), "_non-zero_", exp, "_", treatment, ".vs.", control, ".pdf"))
nonzero
dev.off() 
## quartz_off_screen 
##                 2

6 RPKM and CPM transformations

# Load GFF annotation 
gff_annot <- load_gff_annotations("../../raw-data/paeruginosa_pa14.gff", 
                                  id_col = "gene_id", type = "gene")
## Returning a df with 16 columns and 5979 rows.
rownames(gff_annot) <- gff_annot$gene_id

head(gff_annot)
##               seqnames start  end width strand    source type score phase
## gene1650835 chromosome   483 2027  1545      + PseudoCAP gene    NA     0
## gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene    NA     0
## gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene    NA     0
## gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene    NA     0
## gene1650843 chromosome  7018 7791   774      - PseudoCAP gene    NA     0
## gene1650845 chromosome  7803 8339   537      - PseudoCAP gene    NA     0
##                 gene_id Name         Dbxref      Alias       name Parent locus
## gene1650835 gene1650835      GeneID:4384099 PA14_00010       dnaA         <NA>
## gene1650837 gene1650837      GeneID:4384100 PA14_00020       dnaN         <NA>
## gene1650839 gene1650839      GeneID:4384101 PA14_00030       recF         <NA>
## gene1650841 gene1650841      GeneID:4384102 PA14_00050       gyrB         <NA>
## gene1650843 gene1650843      GeneID:4385186 PA14_00060 PA14_00060         <NA>
## gene1650845 gene1650845      GeneID:4385187 PA14_00070 PA14_00070         <NA>
head(rawcounts)
##             SK082 SK083 SK084 SK085 SK086 SK087
## gene1650835   150   120   137  1579  1694  1158
## gene1650837   338   251   409  1732  2280  1356
## gene1650839   353   264   300   377   454   293
## gene1650841   266   226   196  1914  2500  1745
## gene1650843   135   128   159   292   389   236
## gene1650845   125    70   101   177   180   124
dim(gff_annot)
## [1] 5979   16
dim(rawcounts)
## [1] 5979    6
summary(rownames(gff_annot) == rownames(rawcounts))
##    Mode   FALSE    TRUE 
## logical     932    5047
gff_annot <- gff_annot[rownames(rawcounts),]
summary(rownames(gff_annot) == rownames(rawcounts))
##    Mode    TRUE 
## logical    5979
# Create an expression object with counts, metadata, and gene info
expt <- create_expt(count_dataframe = rawcounts,
                    metadata = metadata, 
                    gene_info = gff_annot)
## Reading the sample metadata.
## Did not find the column: sampleid.
## The rownames do not appear numeric, using them.
## The sample definitions comprises: 6 rows(samples) and 8 columns(metadata fields).
## Matched 5979 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 5979 features and 6 samples.
# Normalize counts log2 CPM
cpm_normalized_exp <- normalize_expt(expt, 
                                     transform = "log2", 
                                     norm = "raw", 
                                     convert = "cpm", 
                                     row_min = "10")
## transform_counts: Found 406 values equal to 0, adding 1 to the matrix.
####### Calculate RPKM ########

# Grab gene lengths from GFF (should be in base pairs)
gene_lengths <- gff_annot$width  
names(gene_lengths) <- rownames(gff_annot)  # set gene names

# Make sure gene_lengths are in the same order as rawcounts rows
gene_lengths <- gene_lengths[rownames(rawcounts)]

# Make DGEList object for edgeR
dge <- DGEList(counts = rawcounts)

# Calculate RPKM (reads per kilobase per million)
rpkm <- rpkm(dge, gene.length = gene_lengths)

# Wrap RPKM in an experiment object too
expt_rpkm <- create_expt(count_dataframe = rpkm,
                         metadata = metadata, 
                         gene_info = gff_annot)
## Reading the sample metadata.
## Did not find the column: sampleid.
## The rownames do not appear numeric, using them.
## The sample definitions comprises: 6 rows(samples) and 8 columns(metadata fields).
## Matched 5979 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 5979 features and 6 samples.
# log2 transform the RPKM (again, no normalization beyond log)
rpkm_normalized_exp <- normalize_expt(expt_rpkm, 
                                      transform = "log2", 
                                      norm = "raw")
## transform_counts: Found 406 values equal to 0, adding 1 to the matrix.
# Get the actual expression matrices from the experiment objects
rpkm <- exprs(rpkm_normalized_exp)
cpm <- exprs(cpm_normalized_exp)

# Merge CPM and RPKM matrices with gene annotation info
cpm_annotated <- merge(gff_annot, cpm, by = 0)
rpkm_annotated <- merge(gff_annot, rpkm, by = 0)

6.1 Heatmap of alginate genes

This generates a small heatmap of the alginate genes across samples to visualize expression.

# Loop through CPM and RPKM to plot both heatmaps
for (type in c("cpm", "rpkm")) {
  
  # Define gene list
  alg_operon_genes <- c(
    "algA", "algF", "algJ", "algI", "algL", "algX", "algG", "algE",
    "algK", "alg44", "alg8", "algD", "mucC", "mucB", "algU", "algW",
    "algP", "algQ", "algR", "algZ", "algC", "algB"
  )

  # Get the right data per type of transformation
  data_annot <- get(paste0(type, "_annotated"))
  
  # Fix rownames using gene name (make unique)
  rownames(data_annot) <- make.names(data_annot$name, unique = TRUE)
  
  # Drop undesired metadata columns
  cols_to_exclude <- c("Row.names","seqnames","start","end","width",
                       "strand","source","type","score","phase",
                       "gene_id","Name","Dbxref","Alias","name",
                       "Parent","locus")
  keep <- !names(data_annot) %in% cols_to_exclude
  expr_data <- data_annot[, keep]
  
  # Extract matrix for alg genes
  alg_genes <- expr_data[alg_operon_genes, , drop = FALSE]
  mat <- alg_genes - rowMeans(alg_genes)
  
  # Pull sample annotations
  anno <- as.data.frame(metadata[, c("condition", "induced")])
  colnames(anno) <- c("Condition", "Induced")
  
  # Color settings for annotation
 # ann_colors <- list(
 #  Condition = c("LB-DMSO" = "#D95F02", "LB-IPTG" = "#66A61E"),
 #  Induced = c("no" = "lightgrey", "yes" = "gray27")
 # )
  
  # Scale data by row (Z-score per gene)
  scaled_mat <- t(scale(t(mat)))

  # Build heatmap
  ht <- Heatmap(
    scaled_mat,
    name = "Z-score",
    top_annotation = HeatmapAnnotation(df = anno#, 
                                       #col = ann_colors
                                       ),
    cluster_rows = TRUE,
    cluster_columns = TRUE,
    row_names_side = "left",
    column_names_side = "bottom",
    column_names_rot = 45,
    row_names_gp = gpar(fontsize = 10),
    column_names_gp = gpar(fontsize = 10),
    show_row_dend = TRUE,
    show_column_dend = TRUE
  )
  
  # Draw and save
  draw(ht)
  
  cairo_pdf(paste0(Sys.Date(), "_alg_heatmap_", type, "_", exp, "_", treatment, ".vs.", control, ".pdf"))
  draw(ht)
  dev.off()
}

7 DESeq

# Create DESeqDataSet
dds <- DESeqDataSetFromMatrix(
  countData = rawcounts,
  colData = metadata,
  design = design_formula
)
## Warning in DESeqDataSet(se, design = design, ignoreRank): some variables in
## design formula are characters, converting to factors
# Check number of genes before filtering
print("Number of genes before filtering:")
## [1] "Number of genes before filtering:"
nrow(dds)
## [1] 5979
# Filter: keep genes with counts >=10 in at least 2 samples
print("Filtering genes with counts >=10 in at least 2 samples")
## [1] "Filtering genes with counts >=10 in at least 2 samples"
keep <- rowSums(counts(dds) >= 10) >= 2 
dds_filtered <- dds[keep, ]

# Check number of genes after filtering
print("Number of genes after filtering:")
## [1] "Number of genes after filtering:"
nrow(dds_filtered)
## [1] 5766
# Run DESeq on the filtered dataset
dds_final <- DESeq(dds_filtered)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
# Show available results
resultsNames(dds_final)
## [1] "Intercept"                  "exp_7_treatment_vs_control"
## [3] "batch_b2_vs_b1"             "batch_b3_vs_b1"
# Plot dispersion estimates
plotDispEsts(dds_final)

8 Save DE tables

res <- results(dds_final, contrast = c("exp_7", "treatment", "control"))
resdf <- as.data.frame(res)
resdf$gene_id <- rownames(resdf)

cpm <- as.data.frame(cpm)
rpkm <- as.data.frame(rpkm)

# append type of value to the dataframe   
colnames(rpkm) <- paste0(colnames(rpkm), "_rpkm")
colnames(cpm) <- paste0(colnames(cpm), "_cpm")
rawcounts2 <- rawcounts
colnames(rawcounts2) <- paste0(colnames(rawcounts2), "_rawcounts")

# ensure column gene_id is there
rpkm$gene_id <- rownames(rpkm)
cpm$gene_id <- rownames(cpm)
rawcounts2$gene_id <- rownames(rawcounts2)

gff_annot <- gff_annot[rownames(resdf),]

dim(resdf)
## [1] 5766    7
# merge with siggenes
resdf <- full_join(resdf, gff_annot, by = "gene_id", copy = FALSE)
head(resdf)
##   baseMean log2FoldChange     lfcSE       stat       pvalue         padj
## 1 661.9531     2.77633336 0.1868037 14.8623060 5.789747e-50 8.387859e-49
## 2 899.9872     1.76530286 0.2001719  8.8189335 1.155551e-18 5.709430e-18
## 3 336.1293    -0.37409484 0.2054728 -1.8206534 6.865955e-02 9.267111e-02
## 4 946.4973     2.49913934 0.1883606 13.2678490 3.556433e-40 3.854585e-39
## 5 206.1019     0.44103212 0.2350589  1.8762620 6.061932e-02 8.269008e-02
## 6 124.0061     0.06078915 0.2788383  0.2180086 8.274224e-01 8.534736e-01
##       gene_id   seqnames start  end width strand    source type score phase
## 1 gene1650835 chromosome   483 2027  1545      + PseudoCAP gene    NA     0
## 2 gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene    NA     0
## 3 gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene    NA     0
## 4 gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene    NA     0
## 5 gene1650843 chromosome  7018 7791   774      - PseudoCAP gene    NA     0
## 6 gene1650845 chromosome  7803 8339   537      - PseudoCAP gene    NA     0
##   Name         Dbxref      Alias       name Parent locus
## 1      GeneID:4384099 PA14_00010       dnaA         <NA>
## 2      GeneID:4384100 PA14_00020       dnaN         <NA>
## 3      GeneID:4384101 PA14_00030       recF         <NA>
## 4      GeneID:4384102 PA14_00050       gyrB         <NA>
## 5      GeneID:4385186 PA14_00060 PA14_00060         <NA>
## 6      GeneID:4385187 PA14_00070 PA14_00070         <NA>
pa_go <- read.csv("../../raw-data/208963_microbes.online.csv", header = TRUE)
head(pa_go)
##   locusId   accession        GI scaffoldId start stop strand      Alias
## 1 2194572 YP_788156.1 116053721       4582   483 2027      + PA14_00010
## 2 2194573 YP_788157.1 116053722       4582  2056 3159      + PA14_00020
## 3 2194574 YP_788158.1 116053723       4582  3169 4278      + PA14_00030
## 4 2194575 YP_788159.1 116053724       4582  4275 6695      + PA14_00050
## 5 2194576 YP_788160.1 116053725       4582  7791 7018      - PA14_00060
## 6 2194577 YP_788161.1 116053726       4582  8339 7803      - PA14_00070
##         name                                                  desc     COG
## 1       dnaA chromosomal replication initiator protein DnaA (NCBI)  COG593
## 2       dnaN                 DNA polymerase III, beta chain (NCBI)  COG592
## 3       recF        DNA replication and repair protein RecF (NCBI) COG1195
## 4       gyrB                           DNA gyrase subunit B (NCBI)  COG187
## 5 PA14_00060                       putative acyltransferase (NCBI)  COG204
## 6 PA14_00070                putative histidinol-phosphatase (NCBI)  COG241
##   COGFun
## 1      L
## 2      L
## 3      L
## 4      L
## 5      I
## 6      E
##                                                                    COGDesc
## 1                            ATPase involved in DNA replication initiation
## 2                      DNA polymerase sliding clamp subunit (PCNA homolog)
## 3                         Recombinational DNA repair ATPase (RecF pathway)
## 4 Type IIA topoisomerase (DNA gyrase/topo II, topoisomerase IV), B subunit
## 5                           1-acyl-sn-glycerol-3-phosphate acyltransferase
## 6                          Histidinol phosphatase and related phosphatases
##                                                                                  TIGRFam
## 1                        TIGR00362 chromosomal replication initiator protein DnaA [dnaA]
## 2                                      TIGR00663 DNA polymerase III, beta subunit [dnaN]
## 3                               TIGR00611 DNA replication and repair protein RecF [recF]
## 4                                                 TIGR01059 DNA gyrase, B subunit [gyrB]
## 5                                                                                       
## 6 TIGR01656 histidinol-phosphate phosphatase domain,TIGR01662 HAD hydrolase, family IIIA
##                                                   TIGRRoles
## 1 DNA metabolism:DNA replication, recombination, and repair
## 2 DNA metabolism:DNA replication, recombination, and repair
## 3 DNA metabolism:DNA replication, recombination, and repair
## 4 DNA metabolism:DNA replication, recombination, and repair
## 5                                                          
## 6           Unknown function:Enzymes of unknown specificity
##                                                                                                                                                                                           GO
## 1                                                                                                                                     GO:0006270,GO:0006275,GO:0003688,GO:0017111,GO:0005524
## 2 GO:0006260,GO:0003677,GO:0003893,GO:0008408,GO:0016449,GO:0019984,GO:0003889,GO:0003894,GO:0015999,GO:0016450,GO:0003890,GO:0003895,GO:0016000,GO:0016451,GO:0003891,GO:0016448,GO:0016452
## 3                                                                                                                                     GO:0006281,GO:0005694,GO:0005524,GO:0017111,GO:0003697
## 4                                                                                                                                     GO:0006304,GO:0006265,GO:0005694,GO:0003918,GO:0005524
## 5                                                                                                                                                                      GO:0008152,GO:0003841
## 6                                                                                                                                                                      GO:0000105,GO:0004401
##         EC                                        ECDesc
## 1                                                       
## 2  2.7.7.7                  DNA-directed DNA polymerase.
## 3                                                       
## 4 5.99.1.3          DNA topoisomerase (ATP-hydrolyzing).
## 5 2.3.1.51 1-acylglycerol-3-phosphate O-acyltransferase.
## 6  3.1.3.-
col_to_remove <- intersect(colnames(pa_go),colnames(resdf))
col_to_remove <- setdiff(col_to_remove, "Alias") # returns all except the second vector

pa_go <- pa_go %>% select(-all_of(col_to_remove))

resdf <- full_join(resdf, rpkm, by = "gene_id", copy = FALSE)
resdf <- full_join(resdf, cpm, by = "gene_id", copy = FALSE)
resdf <- full_join(resdf, rawcounts2, by = "gene_id", copy = FALSE)
#resdf <- full_join(resdf, pa_go, by = "Alias", copy = FALSE)
resdf <- merge(resdf, pa_go, by = "Alias", copy = FALSE)

head(resdf)
##        Alias baseMean log2FoldChange     lfcSE       stat       pvalue
## 1 PA14_00010 661.9531     2.77633336 0.1868037 14.8623060 5.789747e-50
## 2 PA14_00020 899.9872     1.76530286 0.2001719  8.8189335 1.155551e-18
## 3 PA14_00030 336.1293    -0.37409484 0.2054728 -1.8206534 6.865955e-02
## 4 PA14_00050 946.4973     2.49913934 0.1883606 13.2678490 3.556433e-40
## 5 PA14_00060 206.1019     0.44103212 0.2350589  1.8762620 6.061932e-02
## 6 PA14_00070 124.0061     0.06078915 0.2788383  0.2180086 8.274224e-01
##           padj     gene_id   seqnames start  end width strand    source type
## 1 8.387859e-49 gene1650835 chromosome   483 2027  1545      + PseudoCAP gene
## 2 5.709430e-18 gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene
## 3 9.267111e-02 gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene
## 4 3.854585e-39 gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene
## 5 8.269008e-02 gene1650843 chromosome  7018 7791   774      - PseudoCAP gene
## 6 8.534736e-01 gene1650845 chromosome  7803 8339   537      - PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK082_rpkm SK083_rpkm
## 1    NA     0      GeneID:4384099       dnaA         <NA>   5.091606   4.892971
## 2    NA     0      GeneID:4384100       dnaN         <NA>   6.719347   6.410163
## 3    NA     0      GeneID:4384101       recF         <NA>   6.773662   6.474446
## 4    NA     0      GeneID:4384102       gyrB         <NA>   5.265142   5.150084
## 5    NA     0      GeneID:4385186 PA14_00060         <NA>   5.917922   5.957298
## 6    NA     0      GeneID:4385187 PA14_00070         <NA>   6.328308   5.620217
##   SK084_rpkm SK085_rpkm SK086_rpkm SK087_rpkm SK082_cpm SK083_cpm SK084_cpm
## 1   5.057935   7.989449   7.833958   7.830711  5.704210  5.503347  5.670183
## 2   7.087401   8.605764   8.744455   8.540827  6.860797  6.551304  7.229142
## 3   6.636371   6.411482   6.421924   6.336705  6.922914  6.623397  6.785493
## 4   4.930738   7.620694   7.747847   7.774559  6.518556  6.401640  6.178307
## 5   6.245160   6.561349   6.716019   6.542347  5.555278  5.594467  5.881108
## 6   6.119653   6.368749   6.138494   6.146263  5.446699  4.748281  5.240425
##   SK085_cpm SK086_cpm SK087_cpm SK082_rawcounts SK083_rawcounts SK084_rawcounts
## 1  8.615052  8.459333  8.456080             150             120             137
## 2  8.748155  8.886879  8.683202             338             251             409
## 3  6.560362  6.570815  6.485495             353             264             300
## 4  8.891988  9.019505  9.046289             266             226             196
## 5  6.196208  6.350426  6.177265             135             128             159
## 6  5.486717  5.259038  5.266713             125              70             101
##   SK085_rawcounts SK086_rawcounts SK087_rawcounts locusId   accession        GI
## 1            1579            1694            1158 2194572 YP_788156.1 116053721
## 2            1732            2280            1356 2194573 YP_788157.1 116053722
## 3             377             454             293 2194574 YP_788158.1 116053723
## 4            1914            2500            1745 2194575 YP_788159.1 116053724
## 5             292             389             236 2194576 YP_788160.1 116053725
## 6             177             180             124 2194577 YP_788161.1 116053726
##   scaffoldId stop                                                  desc     COG
## 1       4582 2027 chromosomal replication initiator protein DnaA (NCBI)  COG593
## 2       4582 3159                 DNA polymerase III, beta chain (NCBI)  COG592
## 3       4582 4278        DNA replication and repair protein RecF (NCBI) COG1195
## 4       4582 6695                           DNA gyrase subunit B (NCBI)  COG187
## 5       4582 7018                       putative acyltransferase (NCBI)  COG204
## 6       4582 7803                putative histidinol-phosphatase (NCBI)  COG241
##   COGFun
## 1      L
## 2      L
## 3      L
## 4      L
## 5      I
## 6      E
##                                                                    COGDesc
## 1                            ATPase involved in DNA replication initiation
## 2                      DNA polymerase sliding clamp subunit (PCNA homolog)
## 3                         Recombinational DNA repair ATPase (RecF pathway)
## 4 Type IIA topoisomerase (DNA gyrase/topo II, topoisomerase IV), B subunit
## 5                           1-acyl-sn-glycerol-3-phosphate acyltransferase
## 6                          Histidinol phosphatase and related phosphatases
##                                                                                  TIGRFam
## 1                        TIGR00362 chromosomal replication initiator protein DnaA [dnaA]
## 2                                      TIGR00663 DNA polymerase III, beta subunit [dnaN]
## 3                               TIGR00611 DNA replication and repair protein RecF [recF]
## 4                                                 TIGR01059 DNA gyrase, B subunit [gyrB]
## 5                                                                                       
## 6 TIGR01656 histidinol-phosphate phosphatase domain,TIGR01662 HAD hydrolase, family IIIA
##                                                   TIGRRoles
## 1 DNA metabolism:DNA replication, recombination, and repair
## 2 DNA metabolism:DNA replication, recombination, and repair
## 3 DNA metabolism:DNA replication, recombination, and repair
## 4 DNA metabolism:DNA replication, recombination, and repair
## 5                                                          
## 6           Unknown function:Enzymes of unknown specificity
##                                                                                                                                                                                           GO
## 1                                                                                                                                     GO:0006270,GO:0006275,GO:0003688,GO:0017111,GO:0005524
## 2 GO:0006260,GO:0003677,GO:0003893,GO:0008408,GO:0016449,GO:0019984,GO:0003889,GO:0003894,GO:0015999,GO:0016450,GO:0003890,GO:0003895,GO:0016000,GO:0016451,GO:0003891,GO:0016448,GO:0016452
## 3                                                                                                                                     GO:0006281,GO:0005694,GO:0005524,GO:0017111,GO:0003697
## 4                                                                                                                                     GO:0006304,GO:0006265,GO:0005694,GO:0003918,GO:0005524
## 5                                                                                                                                                                      GO:0008152,GO:0003841
## 6                                                                                                                                                                      GO:0000105,GO:0004401
##         EC                                        ECDesc
## 1                                                       
## 2  2.7.7.7                  DNA-directed DNA polymerase.
## 3                                                       
## 4 5.99.1.3          DNA topoisomerase (ATP-hydrolyzing).
## 5 2.3.1.51 1-acylglycerol-3-phosphate O-acyltransferase.
## 6  3.1.3.-
write.csv(resdf, paste0(Sys.Date() , "_results_",exp, "_", treatment,".vs.", control,".csv"), row.names = FALSE)

9 Save DEG list

# filter for significantly differentially expressed genes (LFC >= 3, padj < pval_cutoff)
dim(resdf)
## [1] 5759   54
head(resdf)
##        Alias baseMean log2FoldChange     lfcSE       stat       pvalue
## 1 PA14_00010 661.9531     2.77633336 0.1868037 14.8623060 5.789747e-50
## 2 PA14_00020 899.9872     1.76530286 0.2001719  8.8189335 1.155551e-18
## 3 PA14_00030 336.1293    -0.37409484 0.2054728 -1.8206534 6.865955e-02
## 4 PA14_00050 946.4973     2.49913934 0.1883606 13.2678490 3.556433e-40
## 5 PA14_00060 206.1019     0.44103212 0.2350589  1.8762620 6.061932e-02
## 6 PA14_00070 124.0061     0.06078915 0.2788383  0.2180086 8.274224e-01
##           padj     gene_id   seqnames start  end width strand    source type
## 1 8.387859e-49 gene1650835 chromosome   483 2027  1545      + PseudoCAP gene
## 2 5.709430e-18 gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene
## 3 9.267111e-02 gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene
## 4 3.854585e-39 gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene
## 5 8.269008e-02 gene1650843 chromosome  7018 7791   774      - PseudoCAP gene
## 6 8.534736e-01 gene1650845 chromosome  7803 8339   537      - PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK082_rpkm SK083_rpkm
## 1    NA     0      GeneID:4384099       dnaA         <NA>   5.091606   4.892971
## 2    NA     0      GeneID:4384100       dnaN         <NA>   6.719347   6.410163
## 3    NA     0      GeneID:4384101       recF         <NA>   6.773662   6.474446
## 4    NA     0      GeneID:4384102       gyrB         <NA>   5.265142   5.150084
## 5    NA     0      GeneID:4385186 PA14_00060         <NA>   5.917922   5.957298
## 6    NA     0      GeneID:4385187 PA14_00070         <NA>   6.328308   5.620217
##   SK084_rpkm SK085_rpkm SK086_rpkm SK087_rpkm SK082_cpm SK083_cpm SK084_cpm
## 1   5.057935   7.989449   7.833958   7.830711  5.704210  5.503347  5.670183
## 2   7.087401   8.605764   8.744455   8.540827  6.860797  6.551304  7.229142
## 3   6.636371   6.411482   6.421924   6.336705  6.922914  6.623397  6.785493
## 4   4.930738   7.620694   7.747847   7.774559  6.518556  6.401640  6.178307
## 5   6.245160   6.561349   6.716019   6.542347  5.555278  5.594467  5.881108
## 6   6.119653   6.368749   6.138494   6.146263  5.446699  4.748281  5.240425
##   SK085_cpm SK086_cpm SK087_cpm SK082_rawcounts SK083_rawcounts SK084_rawcounts
## 1  8.615052  8.459333  8.456080             150             120             137
## 2  8.748155  8.886879  8.683202             338             251             409
## 3  6.560362  6.570815  6.485495             353             264             300
## 4  8.891988  9.019505  9.046289             266             226             196
## 5  6.196208  6.350426  6.177265             135             128             159
## 6  5.486717  5.259038  5.266713             125              70             101
##   SK085_rawcounts SK086_rawcounts SK087_rawcounts locusId   accession        GI
## 1            1579            1694            1158 2194572 YP_788156.1 116053721
## 2            1732            2280            1356 2194573 YP_788157.1 116053722
## 3             377             454             293 2194574 YP_788158.1 116053723
## 4            1914            2500            1745 2194575 YP_788159.1 116053724
## 5             292             389             236 2194576 YP_788160.1 116053725
## 6             177             180             124 2194577 YP_788161.1 116053726
##   scaffoldId stop                                                  desc     COG
## 1       4582 2027 chromosomal replication initiator protein DnaA (NCBI)  COG593
## 2       4582 3159                 DNA polymerase III, beta chain (NCBI)  COG592
## 3       4582 4278        DNA replication and repair protein RecF (NCBI) COG1195
## 4       4582 6695                           DNA gyrase subunit B (NCBI)  COG187
## 5       4582 7018                       putative acyltransferase (NCBI)  COG204
## 6       4582 7803                putative histidinol-phosphatase (NCBI)  COG241
##   COGFun
## 1      L
## 2      L
## 3      L
## 4      L
## 5      I
## 6      E
##                                                                    COGDesc
## 1                            ATPase involved in DNA replication initiation
## 2                      DNA polymerase sliding clamp subunit (PCNA homolog)
## 3                         Recombinational DNA repair ATPase (RecF pathway)
## 4 Type IIA topoisomerase (DNA gyrase/topo II, topoisomerase IV), B subunit
## 5                           1-acyl-sn-glycerol-3-phosphate acyltransferase
## 6                          Histidinol phosphatase and related phosphatases
##                                                                                  TIGRFam
## 1                        TIGR00362 chromosomal replication initiator protein DnaA [dnaA]
## 2                                      TIGR00663 DNA polymerase III, beta subunit [dnaN]
## 3                               TIGR00611 DNA replication and repair protein RecF [recF]
## 4                                                 TIGR01059 DNA gyrase, B subunit [gyrB]
## 5                                                                                       
## 6 TIGR01656 histidinol-phosphate phosphatase domain,TIGR01662 HAD hydrolase, family IIIA
##                                                   TIGRRoles
## 1 DNA metabolism:DNA replication, recombination, and repair
## 2 DNA metabolism:DNA replication, recombination, and repair
## 3 DNA metabolism:DNA replication, recombination, and repair
## 4 DNA metabolism:DNA replication, recombination, and repair
## 5                                                          
## 6           Unknown function:Enzymes of unknown specificity
##                                                                                                                                                                                           GO
## 1                                                                                                                                     GO:0006270,GO:0006275,GO:0003688,GO:0017111,GO:0005524
## 2 GO:0006260,GO:0003677,GO:0003893,GO:0008408,GO:0016449,GO:0019984,GO:0003889,GO:0003894,GO:0015999,GO:0016450,GO:0003890,GO:0003895,GO:0016000,GO:0016451,GO:0003891,GO:0016448,GO:0016452
## 3                                                                                                                                     GO:0006281,GO:0005694,GO:0005524,GO:0017111,GO:0003697
## 4                                                                                                                                     GO:0006304,GO:0006265,GO:0005694,GO:0003918,GO:0005524
## 5                                                                                                                                                                      GO:0008152,GO:0003841
## 6                                                                                                                                                                      GO:0000105,GO:0004401
##         EC                                        ECDesc
## 1                                                       
## 2  2.7.7.7                  DNA-directed DNA polymerase.
## 3                                                       
## 4 5.99.1.3          DNA topoisomerase (ATP-hydrolyzing).
## 5 2.3.1.51 1-acylglycerol-3-phosphate O-acyltransferase.
## 6  3.1.3.-
summary(is.na(resdf$log2FoldChange))
##    Mode   FALSE 
## logical    5759
summary(is.na(resdf$padj))
##    Mode   FALSE 
## logical    5759
sig_genes <- resdf[abs(resdf$log2FoldChange) >= logfc_cutoff & resdf$padj < pval_cutoff, ]  %>% drop_na(log2FoldChange)
sig_genes$direction <- ifelse(sig_genes$log2FoldChange > 0, "up", "down")

summary(is.na(sig_genes$log2FoldChange))
##    Mode   FALSE 
## logical    1509
summary(is.na(sig_genes$padj))
##    Mode   FALSE 
## logical    1509
dim(sig_genes)
## [1] 1509   55
head(sig_genes)
##        Alias  baseMean log2FoldChange     lfcSE      stat       pvalue
## 1 PA14_00010 661.95315       2.776333 0.1868037 14.862306 5.789747e-50
## 2 PA14_00050 946.49731       2.499139 0.1883606 13.267849 3.556433e-40
## 3 PA14_00100  78.49348       3.369882 0.4056361  8.307649 9.761648e-17
## 4 PA14_00140  33.89249       2.492105 0.5289741  4.711205 2.462560e-06
## 5 PA14_00280 159.66526       2.686898 0.3014627  8.912872 4.972734e-19
## 6 PA14_00520  32.19383       2.257154 0.5981242  3.773721 1.608308e-04
##           padj     gene_id   seqnames start   end width strand    source type
## 1 8.387859e-49 gene1650835 chromosome   483  2027  1545      + PseudoCAP gene
## 2 3.854585e-39 gene1650841 chromosome  4275  6695  2421      + PseudoCAP gene
## 3 4.359850e-16 gene1650851 chromosome 12488 13435   948      - PseudoCAP gene
## 4 5.727761e-06 gene1650859 chromosome 15621 16274   654      + PseudoCAP gene
## 5 2.508555e-18 gene1650881 chromosome 25757 26674   918      + PseudoCAP gene
## 6 3.143561e-04 gene1650919 chromosome 54577 54699   123      + PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK082_rpkm SK083_rpkm
## 1    NA     0      GeneID:4384099       dnaA         <NA>   5.091606   4.892971
## 2    NA     0      GeneID:4384102       gyrB         <NA>   5.265142   5.150084
## 3    NA     0      GeneID:4385190       glyQ         <NA>   2.410146   2.505718
## 4    NA     0      GeneID:4385194 PA14_00140         <NA>   2.635208   1.935910
## 5    NA     0      GeneID:4384742       hemF         <NA>   4.146585   3.836798
## 6    NA     0      GeneID:4384761 PA14_00520         <NA>   5.887614   4.461916
##   SK084_rpkm SK085_rpkm SK086_rpkm SK087_rpkm SK082_cpm SK083_cpm SK084_cpm
## 1   5.057935   7.989449   7.833958   7.830711  5.704210  5.503347  5.670183
## 2   4.930738   7.620694   7.747847   7.774559  6.518556  6.401640  6.178307
## 3   2.156835   5.869857   5.245471   5.628967  2.347917  2.442544  2.097431
## 4   2.716254   4.721064   4.973284   4.821764  2.140475  1.510117  2.215322
## 5   3.500838   6.380098   6.615426   6.729057  4.030409  3.722355  3.388743
## 6   3.305598   6.829935   7.171712   7.140965  3.028401  1.843045  1.065680
##   SK085_cpm SK086_cpm SK087_cpm SK082_rawcounts SK083_rawcounts SK084_rawcounts
## 1  8.615052  8.459333  8.456080             150             120             137
## 2  8.891988  9.019505  9.046289             266             226             196
## 3  5.794169  5.170514  5.553524              12              12               9
## 4  4.137080  4.384741  4.235865              10               5              10
## 5  6.258210  6.493306  6.606838              45              33              26
## 6  3.894362  4.218080  4.188796              21               7               3
##   SK085_rawcounts SK086_rawcounts SK087_rawcounts locusId   accession        GI
## 1            1579            1694            1158 2194572 YP_788156.1 116053721
## 2            1914            2500            1745 2194575 YP_788159.1 116053724
## 3             220             169             152 2194580 YP_788164.1 116053729
## 4              67              96              59 2194584 YP_788168.1 116053733
## 5             305             430             319 2194595 YP_788179.1 116053744
## 6              56              85              57 2194614 YP_788198.1 116053763
##   scaffoldId  stop                                                  desc
## 1       4582  2027 chromosomal replication initiator protein DnaA (NCBI)
## 2       4582  6695                           DNA gyrase subunit B (NCBI)
## 3       4582 12488             glycyl-tRNA synthetase alpha chain (NCBI)
## 4       4582 16274                           hypothetical protein (NCBI)
## 5       4582 26674        coproporphyrinogen III oxidase, aerobic (NCBI)
## 6       4582 54699                           hypothetical protein (NCBI)
##       COG COGFun
## 1  COG593      L
## 2  COG187      L
## 3  COG752      J
## 4 COG1738      S
## 5  COG408      H
## 6               
##                                                                    COGDesc
## 1                            ATPase involved in DNA replication initiation
## 2 Type IIA topoisomerase (DNA gyrase/topo II, topoisomerase IV), B subunit
## 3                                    Glycyl-tRNA synthetase, alpha subunit
## 4                                        Uncharacterized conserved protein
## 5                                           Coproporphyrinogen III oxidase
## 6                                                                         
##                                                           TIGRFam
## 1 TIGR00362 chromosomal replication initiator protein DnaA [dnaA]
## 2                          TIGR01059 DNA gyrase, B subunit [gyrB]
## 3            TIGR00388 glycine--tRNA ligase, alpha subunit [glyQ]
## 4      TIGR00697 conserved hypothetical integral membrane protein
## 5                                                                
## 6                                                                
##                                                   TIGRRoles
## 1 DNA metabolism:DNA replication, recombination, and repair
## 2 DNA metabolism:DNA replication, recombination, and repair
## 3                     Protein synthesis:tRNA aminoacylation
## 4                           Hypothetical proteins:Conserved
## 5                                                          
## 6                                                          
##                                                       GO       EC
## 1 GO:0006270,GO:0006275,GO:0003688,GO:0017111,GO:0005524         
## 2 GO:0006304,GO:0006265,GO:0005694,GO:0003918,GO:0005524 5.99.1.3
## 3            GO:0006426,GO:0009345,GO:0005524,GO:0004820 6.1.1.14
## 4                                                                
## 5                                  GO:0006779,GO:0004109  1.3.3.3
## 6                                                                
##                                 ECDesc direction
## 1                                             up
## 2 DNA topoisomerase (ATP-hydrolyzing).        up
## 3                Glycine--tRNA ligase.        up
## 4                                             up
## 5          Coproporphyrinogen oxidase.        up
## 6                                             up
write.csv(sig_genes, paste0(Sys.Date(),"_significantgenes_", exp, "_", treatment,".vs.", control,".csv"), row.names = FALSE)

10 PCA plot

vst <- DESeqDataSetFromMatrix(countData = rawcounts, colData = metadata, design = ~ exp_7 + batch)
## Warning in DESeqDataSet(se, design = design, ignoreRank): some variables in
## design formula are characters, converting to factors
# Variance stabilizing transformations
vsd <- vst(vst, blind = TRUE)

# PCA plot
pcaData <- plotPCA(vsd, intgroup = c("exp_7", "batch", "condition"), returnData = TRUE)
## using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

# Calculate the maximum absolute value among PC1 and PC2
max_abs_val <- max(c(abs(min(pcaData$PC1)), abs(min(pcaData$PC2)), abs(max(pcaData$PC1)), abs(max(pcaData$PC2))))

axis_size <- 10
theme_set(theme_minimal(base_family = "Arial"))

pca <- ggplot(pcaData, aes(PC1, PC2, color = condition, shape = condition)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar[2], "% variance")) +
  scale_colour_brewer(palette = "Dark2") +
  scale_shape_manual(values = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) +
  coord_fixed(ratio = 1, xlim = c(-max_abs_val, max_abs_val), ylim = c(-max_abs_val, max_abs_val)) +
  labs(color = "condition", shape = "condition") +
  guides(shape = guide_legend(title = "Condition"),  # Adjust size of shape legend
    color = guide_legend(title = "Condition")) +
  theme(
    panel.grid = element_blank(),
    panel.background = element_blank(),
    axis.text = element_text(size = axis_size),
    axis.ticks = element_line(linewidth = 0.2),
     axis.line = element_line(linewidth = 0, color = "black"),  # Set the axis line linewidth
   panel.border = element_rect(fill = NA, linewidth = 0.5),  # Set the panel border linewidth
  legend.key = element_rect(fill = "white", color = NA)  # Set legend key background to white and remove border
  )

print(pca)

cairo_pdf(paste0(Sys.Date(),"_pca_",exp, "_", treatment,".vs.", control,".pdf", sep = ""))
pca
dev.off()
## quartz_off_screen 
##                 2

11 Volcano plot

sequence <- c("treatment")

for (i in sequence) {
    set.seed(0)
    res <- results(dds_final, contrast = c("exp_7", i, "control"))

  gp2 <- wes_palettes$Zissou1
  key <- read.csv("../../raw-data/pa14_gene_key.csv",  header = TRUE)

  rownames(key) <- key$gene_id

  res <- merge(key, as.data.frame(res), by=0)
  res <- as.data.frame(res)
  res$Alias <- rownames(res)

 # Define gene list
  alg_genes <- c(
    "algA", "algF", "algJ", "algI", "algL", "algX", "algG", "algE",
    "algK", "alg44", "alg8", "algD", "mucC", "mucB", "algU", "algW",
    "algP", "algQ", "algR", "algZ", "algC", "algB"
  )

logfc_cutoff
keyvals <- ifelse(
 res$log2FoldChange <= -logfc_cutoff & res$padj <= pval_cutoff, gp2[1],
  ifelse(res$log2FoldChange >= logfc_cutoff & res$padj <= pval_cutoff, gp2[5],
         'lightgrey'))
keyvals[is.na(keyvals)] <- 'lightgrey'
names(keyvals)[keyvals == gp2[5]] <- 'Up-regulated'
names(keyvals)[keyvals == 'lightgrey'] <- 'NS'
names(keyvals)[keyvals == gp2[1]] <- 'Down-regulated'

volcano <- EnhancedVolcano(res,
                     lab = res[["name"]],
                     selectLab = alg_genes,
                     x = 'log2FoldChange',
                     y = 'padj',
                     xlab = bquote(~Log[2]~ 'fold change'),
                     pCutoff = pval_cutoff,
                     FCcutoff = logfc_cutoff,
                     cutoffLineType = "dashed",
                     pointSize = 1,
                     labSize = 3.0,
                     axisLabSize = 14,
                     labCol = 'black',
                     labFace = 'bold',
                     #col = c('grey', gp2[2], gp2[3], gp2[1]),
                     colCustom = keyvals,
                     colAlpha = 5/5,
                     legendPosition = 'bottom',
                     legendLabSize = 12,
                     legendIconSize = 4.0,
                     drawConnectors = TRUE,
                     arrowheads = FALSE,
                     widthConnectors = 0.2,
                     gridlines.major = FALSE,
                     borderWidth = 0.3,
                     gridlines.minor = FALSE,
                     title = paste0(treatment," vs ", control, sep = ""),
                     subtitle = "",
                     #caption = paste0("total = ", nrow(toptable), " variables"),
                     caption = paste0("Volcano plot with log2 FC of ", logfc_cutoff," and P value of ",pval_cutoff, "."),
                     max.overlaps = 30,
                     #ylim = c(0,10),
                     colConnectors = 'black') + 
      theme(axis.ticks=element_line(linewidth =0.2)) # +
 # scale_x_continuous(breaks = c(-5, -2.5, 0, 2.5, 5), limits = c(-6,6))

print(volcano)

cairo_pdf(paste0(Sys.Date(),"_volcano_", exp, "_", treatment,".vs.", control,".pdf", sep = ""))
print(volcano)
dev.off()
}

12 MA plot

sequence <- c("treatment")

for (i in sequence) {
    set.seed(0)

res <- results(dds_final, contrast = c("exp_7", i, "control"))

gp2 <- wes_palettes$Zissou1

res$gene_id <- rownames(res)
res <- as.data.frame(res)
head(res)
res <- full_join(key, as.data.frame(res), by="gene_id")
rownames(res) <- res$Alias

any(is.na(res))  # Check if there are any NAs

res <- res %>% filter(!is.na(baseMean))


ma <- ggmaplot(res, 
               fdr = pval_cutoff, 
               fc = 2^(logfc_cutoff), 
               size = 1,
               palette = c((gp2[5]), (gp2[1])),
               select.top.method = "fc",
             #  ylim = c(-15,15),
               legend = "bottom", 
               title = paste0(treatment," vs ", control, sep = ""),
              subtitle = paste0("Volcano plot with log2 FC of ", logfc_cutoff," and P value of ",pval_cutoff, "."),
               font.label = c( 12), 
             label.rectangle = FALSE,
              genenames = res$name,
              font.legend = c(12),
               font.main = c("bold", 14),
               alpha = 1.5,
               ggtheme = ggplot2::theme(panel.grid =element_blank(),
                                        axis.text = element_text(size = 12),
                                        axis.title = element_text(size = 14),
                                        panel.background = element_blank(),
                                        panel.border = element_rect(fill = NA))) 
print(ma)

cairo_pdf(paste0(Sys.Date(),"_ma_", exp, "_", treatment,".vs.", control,".pdf"))
print(ma)
dev.off()
}

LS0tCnRpdGxlOiAiMjAyNV9leHBfN19hbGdpbmF0ZV9ERUciCmF1dGhvcjogIk5vdXIgRWwgSHVzc2VpbmkiCmRhdGU6ICIyMDI1IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IGZhbHNlICAjIEVuc3VyZXMgVE9DIGlzIGV4cGFuZGVkIGJ5IGRlZmF1bHQKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgdGhlbWU6CiAgICAgIGJvb3Rzd2F0Y2g6IHplcGh5cgogICAgY3NzOiBzdHlsZS5jc3MgICMgTGluayB0byB5b3VyIGN1c3RvbSBDU1MgZmlsZQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoImthYmxlRXh0cmEiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoImdnZm9yY2UiKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpsaWJyYXJ5KCJwaGVhdG1hcCIpCmxpYnJhcnkoIndlc2FuZGVyc29uIikKbGlicmFyeSgiRW5oYW5jZWRWb2xjYW5vIikKbGlicmFyeSgiZ2dwdWJyIikKbGlicmFyeSgiaHBnbHRvb2xzIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJ0aWJibGUiKSAKbGlicmFyeSgiZWRnZVIiKQpsaWJyYXJ5KCJnZW5lZmlsdGVyIikKbGlicmFyeSgicGhlYXRtYXAiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoIkNvbXBsZXhIZWF0bWFwIikKbGlicmFyeSgiZ29zZXEiKQpsaWJyYXJ5KCJwbHlyIikKbGlicmFyeSgiZ2VvbXRleHRwYXRoIikKYGBgCgojIE92ZXJ2aWV3CgpgYGB7ciBzYW1wbGVfdGFibGUsIGVjaG89RkFMU0V9CiMgTG9hZCBtZXRhZGF0YSBDU1YgZmlsZSBpbnRvIGEgZGF0YWZyYW1lLCB1c2luZyB0aGUgZmlyc3QgY29sdW1uIGFzIHJvdyBuYW1lcwptZXRhZGF0YSA8LSByZWFkLmNzdigiLi4vLi4vcmF3LWRhdGEvbWV0YWRhdGFfYWxnaW5hdGVfdnRsLmNzdiIsIHJvdy5uYW1lcyA9IDEsIGhlYWRlciA9IFRSVUUpCgojIEZpbHRlciB0aGUgZGF0YSB0byBpbmNsdWRlIG9ubHkgcm93cyB3aGVyZSBleHBfNyBpcyBlaXRoZXIgImNvbnRyb2wiIG9yICJ0cmVhdG1lbnQiCiMgVGhlbiByZW1vdmUgb3RoZXIgZXhwZXJpbWVudHMgKGV4cF8yIHRvIGV4cF82KQptZXRhZGF0YSA8LSBmaWx0ZXIobWV0YWRhdGEsIGV4cF83ICVpbiUgYygiY29udHJvbCIsICJ0cmVhdG1lbnQiKSkgJT4lCiAgICBzZWxlY3QoYmF0Y2gsIGNvbmRpdGlvbiwgbWVkaWEsIHRyZWF0bWVudCwgaW5kdWNlZCwgZXhwXzcpIAoKIyBEaXNwbGF5IHRoZSBjbGVhbmVkIG1ldGFkYXRhIHRhYmxlIHVzaW5nIGtuaXRyOjprYWJsZSBhbmQga2FibGVFeHRyYSBzdHlsaW5nCm1ldGFkYXRhICU+JQogIGtibCgpICU+JSAgIyBDcmVhdGUgYSBiYXNpYyB0YWJsZQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IFRSVUUpICAjIEFwcGx5IGEgY2xhc3NpYyB0YWJsZSBzdHlsZSB3aXRoIGZ1bGwgd2lkdGgKYGBgIAoKIyBQcm9qZWN0IHZhcmlhYmxlcwpgYGB7ciBwcm9qZWN0X3BhcmFtZXRlcnMsIGVjaG89RkFMU0V9CiMgRGVmaW5lIHRoZSBsYWJlbHMgZm9yIGNvbnRyb2wgYW5kIHRyZWF0bWVudCBncm91cHMgdXNlZCBpbiB0aGUgZXhwZXJpbWVudApoZWFkKG1ldGFkYXRhKQojIEV4dHJhY3QgY29udHJvbCBhbmQgdHJlYXRtZW50IGNvbmRpdGlvbnMgYmFzZWQgb24gYGV4cF83YCBsYWJlbHMKY29udHJvbCA8LSBtZXRhZGF0YVttZXRhZGF0YSRleHBfNyA9PSAiY29udHJvbCIsIF0KdHJlYXRtZW50IDwtIG1ldGFkYXRhW21ldGFkYXRhJGV4cF83ID09ICJ0cmVhdG1lbnQiLCBdCgpjb250cm9sIDwtIHVuaXF1ZShjb250cm9sJGNvbmRpdGlvbikKdHJlYXRtZW50IDwtIHVuaXF1ZSh0cmVhdG1lbnQkY29uZGl0aW9uKQoKcHJpbnQocGFzdGUwKCJUaGUgY29udHJvbCBpczogIiwgY29udHJvbCkpCnByaW50KHBhc3RlMCgiVGhlIHRyZWF0bWVudCBpczogIiwgdHJlYXRtZW50KSkKCiMgU2V0IGRlZmF1bHQgdGV4dCBzaXplcyBmb3IgcGxvdHMKdGV4dC5zaXplIDwtIDEyICAgIApheGlzLnRleHQuc2l6ZSA8LSAxNAoKbG9nZmNfY3V0b2ZmIDwtIDIKcHZhbF9jdXRvZmYgPC0gMC4wMQoKIyBTZXQgdmFyaWFibGVzIGZvciB0aGUgcHJvamVjdCB1c2VkIGluIGZpbGVuYW1lcyBhbmQgcGxvdCB0aXRsZXMKcHJvamVjdCA8LSAib3JuX2FsZ2luYXRlX3JuYXNlcSIKZXhwIDwtICJleHBfNyIgICAgICAgICAgICAgICAgICAgIApgYGAKCmBgYHtyIHJhd2RhdGF9CiMgTG9hZCByYXcgY291bnQgZGF0YQpyYXdjb3VudHMgPC0gcmVhZC5jc3YoIi4uLy4uL3Jhdy1kYXRhL2h0c2VxX1NLX3VuZmlsdGVyZWRfcmV2ZXJzZV9zdHJhbmRfY291bnQuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLCBoZWFkZXIgPSBUUlVFKQoKIyBBcHBlbmQgYSBwcmVmaXggdG8gdGhlIGJhdGNoIGFuZCBydW4gY29sdW1ucyB0byB0dXJuIHRvIGNoYXJhY3RlciBjbGFzcwptZXRhZGF0YVtbImJhdGNoIl1dIDwtIHBhc3RlMCgiYiIsIG1ldGFkYXRhW1siYmF0Y2giXV0pCm1ldGFkYXRhW1sicnVuIl1dIDwtIHBhc3RlMCgiciIsIG1ldGFkYXRhW1sicnVuIl1dKQoKIyBTdWJzZXQgdGhlIHJhd2NvdW50cyBkYXRhZnJhbWUgdG8gb25seSBpbmNsdWRlIHNhbXBsZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBleHBlcmltZW50CnNhbXBsZXMgPC0gcm93bmFtZXMobWV0YWRhdGEpCnJhd2NvdW50cyA8LSBzZWxlY3QocmF3Y291bnRzLCBhbGxfb2Yoc2FtcGxlcykpCgojIEVuc3VyZSB0aGF0IHRoZSBvcmRlciBvZiBzYW1wbGVzIGluIG1ldGFkYXRhIG1hdGNoZXMgdGhlIG9yZGVyIG9mIGNvbHVtbnMgaW4gcmF3Y291bnRzCmFsbChyb3duYW1lcyhtZXRhZGF0YSkgPT0gY29sbmFtZXMocmF3Y291bnRzKSkgICMgU2hvdWxkIHJldHVybiBUUlVFIGlmIG9yZGVyIGlzIGNvcnJlY3QKCiMgRGVmaW5lIHRoZSBkZXNpZ24gZm9ybXVsYSBmb3IgREVTZXEyLCBpbmNsdWRpbmcgbWFpbiBjb25kaXRpb24gYW5kIGJhdGNoIGVmZmVjdApkZXNpZ25fZm9ybXVsYSA8LSB+IGV4cF83ICsgYmF0Y2gKCiMgQ3JlYXRlIERFU2VxMiBkYXRhc2V0IG9iamVjdCBmcm9tIHRoZSBmaWx0ZXJlZCBjb3VudCBtYXRyaXggYW5kIG1ldGFkYXRhCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KAogIGNvdW50RGF0YSA9IHJhd2NvdW50cywKICBjb2xEYXRhID0gbWV0YWRhdGEsCiAgZGVzaWduID0gZGVzaWduX2Zvcm11bGEKKQpgYGAKCgojIExpYnJhcnkgc2l6ZSBwZXIgc2FtcGxlCmBgYHtyIGxpYnJhcnlfc2l6ZX0KIyBTdW0gdXAgdGhlIGNvdW50cyBmb3IgZWFjaCBzYW1wbGUKcmF3Y291bnRzX3N1bXMgPC0gY29sU3VtcyhyYXdjb3VudHMpCgojIFR1cm4gaXQgaW50byBhIGRhdGEgZnJhbWUKZGF0YSA8LSBkYXRhLmZyYW1lKAogIENhdGVnb3J5ID0gbmFtZXMocmF3Y291bnRzX3N1bXMpLAogIENvdW50ID0gYXMubnVtZXJpYyhyYXdjb3VudHNfc3VtcykKKQoKIyBNYWtlIHN1cmUgc2FtcGxlIG9yZGVyIGlzIGNvbnNpc3RlbnQKZGF0YSA8LSBkYXRhICU+JQogIG11dGF0ZShDYXRlZ29yeSA9IGZhY3RvcihDYXRlZ29yeSwgbGV2ZWxzID0gc29ydCh1bmlxdWUoQ2F0ZWdvcnkpKSkpCgojIFBsb3QgYmFyIGNoYXJ0IG9mIGxpYnJhcnkgc2l6ZXMKcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBDYXRlZ29yeSwgeSA9IENvdW50LCBmaWxsID0gQ2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAjIGNvb3JkX2ZsaXAoKSAjIGZsaXAgaWYgdG9vIG1hbnkgc2FtcGxlcyB0byByZWFkIGxhYmVscyBlYXNpbHkKICBsYWJzKHkgPSAiTGlicmFyeSBzaXplIChNKSIsIHggPSBOVUxMKSArICAjIHJlbW92ZSB4IGxhYmVsLCByZW5hbWUgeSBheGlzCiAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKyAgIyBvcHRpb25hbCBjb2xvciBwYWxldHRlCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoc2NhbGUgPSAxZS02KSwgICMgc2hvdyBjb3VudHMgaW4gbWlsbGlvbnMKICAgIGxpbWl0cyA9IGMoMCwgKG1heChkYXRhJENvdW50KSArIDFlNikpICAgICAgICAjIGFkZCBhIGJpdCBvZiBzcGFjZSBvbiB0b3AKICApICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LnNpemUsIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksICAjIHNsYW50IGxhYmVscwogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gYXhpcy50ZXh0LnNpemUpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRleHQuc2l6ZSksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAgIyBubyBsZWdlbmQgbmVlZGVkIHNpbmNlIGVhY2ggYmFyIGlzIGEgZGlmZmVyZW50IHNhbXBsZQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgU2hvdyB0aGUgcGxvdApwCgojIFNhdmUgdGhlIHBsb3QgYXMgYSBQREYgd2l0aCB0b2RheeKAmXMgZGF0ZSBhbmQgcHJvamVjdCBuYW1lCmdnc2F2ZShwYXN0ZTAoU3lzLkRhdGUoKSwgIl9saWJyYXJ5X3NpemVfIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwiLnZzLiIsIGNvbnRyb2wsICIucGRmIiksIGRldmljZSA9ICJwZGYiKQpgYGAKCiMgRXhwcmVzc2lvbiBkaXN0cmlidXRpb24KCmBgYHtyIGV4cHJlc3Npb25fZGlzdHJpYnV0aW9ufQoKIyBTdGFjayByYXdjb3VudHMgaW50byBzaW5nbGUgdmVjdG9yIApkYXQgPC0gc3RhY2socmF3Y291bnRzKQoKIyBGb3JtYXQgZXhwcmVzc2lvbiBkaXN0cmlidXRpb24gcGxvdCB3aXRoIHRoZSBleHByZXNzaW9uIGxldmVsIGFuZCBkZW5zaXR5IApleHByZXNzaW9uX2Rpc3QgPC0gZ2dwbG90KGRhdCwgYWVzKHggPSBsb2cyKHZhbHVlcysxKSwgIGZpbGw9aW5kLCBsYWJlbCA9IGluZCApKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIAogIHlsYWIoIkRlbnNpdHkiKSArIAogIGdlb21fdGV4dGRlbnNpdHkoaGp1c3QgPSAieW1heCIsIHZqdXN0ID0gMCwKICAgICAgICAgICB0ZXh0X29ubHkgPSBUUlVFLCB0ZXh0X3Ntb290aGluZyA9IDIwKSArIAogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gdGV4dC5zaXplKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBheGlzLnRleHQuc2l6ZSksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRleHQuc2l6ZSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBheGlzLnRleHQuc2l6ZSksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yKSwKICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9ibGFuaygpKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDE1KSkKCmV4cHJlc3Npb25fZGlzdAoKI3NhdmUgZmlndXJlCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwgIl9leHByZXNzaW9uX2Rpc3RfIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwgIi52cy4iLCBjb250cm9sLCAiLnBkZiIpKQpleHByZXNzaW9uX2Rpc3QKZGV2Lm9mZigpIAoKYGBgCgojIE5vbi16ZXJvIGdlbmVzIG9ic2VydmVkCgpgYGB7ciBub24temVyb19nZW5lc30KIyBQcmVwYXJlIGRhdGEgYnkgZ2V0dGluZyBsaWJyYXJ5IHNpemVzIGFuZCBub24temVybyBjb3VudHMKeCA8LSBjb2xTdW1zKHJhd2NvdW50cykKeSA8LSBjb2xTdW1zKHJhd2NvdW50cyAhPSAwKSAKZGYgPC0gZGF0YS5mcmFtZSh4LHkpCmRmJGluZCA8LSByb3duYW1lcyhkZikKCiMgQ2FsY3VsYXRlIGF4aXMgbGltaXRzCnhfbWluIDwtIG1pbihkZiR4KQp4X21heCA8LSBtYXgoZGYkeCkKeV9taW4gPC0gbWluKGRmJHkpCnlfbWF4IDwtIG1heChkZiR5KQoKIyBOb24temVybyBwbG90Cm5vbnplcm8gPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSBpbmQsIGxhYmVsID0gaW5kKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoaGp1c3QgPSAtMC4xLCB2anVzdCA9IC0wLjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoeV9taW4sIHlfbWF4KSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKHhfbWluLTFlMywgeF9tYXgrOWU1KSwKICAgIGxhYmVscyA9IHNjYWxlczo6Y29tbWFfZm9ybWF0KHNjYWxlID0gMWUtNiwgIGFjY3VyYWN5ID0gMSkgICMgRm9ybWF0IGxhYmVscyB3aXRob3V0IGRlY2ltYWxzCiAgKSArCiAgeGxhYigiTWlsbGlvbnMgb2YgcmVhZHMiKSArIHlsYWIoIk51bWJlciBvZiBub24temVybyBnZW5lcyBvYnNlcnZlZCIpICsKICBsYWJzKGNvbG9yID0gIlNhbXBsZSIpICsgCiAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LnNpemUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gdGV4dC5zaXplKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBjb29yZF9jYXJ0ZXNpYW4oKQoKIyBTaG93IG5vbnplcm8gcGxvdApub256ZXJvCgojIFNhdmUgcGxvdAoKY2Fpcm9fcGRmKHBhc3RlMChTeXMuRGF0ZSgpLCAiX25vbi16ZXJvXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsICIudnMuIiwgY29udHJvbCwgIi5wZGYiKSkKbm9uemVybwpkZXYub2ZmKCkgCgpgYGAKCiMgUlBLTSBhbmQgQ1BNIHRyYW5zZm9ybWF0aW9ucwpgYGB7ciBkYXRhX3RyYW5zZm9ybWF0aW9uc30KIyBMb2FkIEdGRiBhbm5vdGF0aW9uIApnZmZfYW5ub3QgPC0gbG9hZF9nZmZfYW5ub3RhdGlvbnMoIi4uLy4uL3Jhdy1kYXRhL3BhZXJ1Z2lub3NhX3BhMTQuZ2ZmIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZF9jb2wgPSAiZ2VuZV9pZCIsIHR5cGUgPSAiZ2VuZSIpCnJvd25hbWVzKGdmZl9hbm5vdCkgPC0gZ2ZmX2Fubm90JGdlbmVfaWQKCmhlYWQoZ2ZmX2Fubm90KQpoZWFkKHJhd2NvdW50cykKZGltKGdmZl9hbm5vdCkKZGltKHJhd2NvdW50cykKCnN1bW1hcnkocm93bmFtZXMoZ2ZmX2Fubm90KSA9PSByb3duYW1lcyhyYXdjb3VudHMpKQpnZmZfYW5ub3QgPC0gZ2ZmX2Fubm90W3Jvd25hbWVzKHJhd2NvdW50cyksXQpzdW1tYXJ5KHJvd25hbWVzKGdmZl9hbm5vdCkgPT0gcm93bmFtZXMocmF3Y291bnRzKSkKCgojIENyZWF0ZSBhbiBleHByZXNzaW9uIG9iamVjdCB3aXRoIGNvdW50cywgbWV0YWRhdGEsIGFuZCBnZW5lIGluZm8KZXhwdCA8LSBjcmVhdGVfZXhwdChjb3VudF9kYXRhZnJhbWUgPSByYXdjb3VudHMsCiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gZ2ZmX2Fubm90KQoKIyBOb3JtYWxpemUgY291bnRzIGxvZzIgQ1BNCmNwbV9ub3JtYWxpemVkX2V4cCA8LSBub3JtYWxpemVfZXhwdChleHB0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInJhdyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19taW4gPSAiMTAiKQoKIyMjIyMjIyBDYWxjdWxhdGUgUlBLTSAjIyMjIyMjIwoKIyBHcmFiIGdlbmUgbGVuZ3RocyBmcm9tIEdGRiAoc2hvdWxkIGJlIGluIGJhc2UgcGFpcnMpCmdlbmVfbGVuZ3RocyA8LSBnZmZfYW5ub3Qkd2lkdGggIApuYW1lcyhnZW5lX2xlbmd0aHMpIDwtIHJvd25hbWVzKGdmZl9hbm5vdCkgICMgc2V0IGdlbmUgbmFtZXMKCiMgTWFrZSBzdXJlIGdlbmVfbGVuZ3RocyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgcmF3Y291bnRzIHJvd3MKZ2VuZV9sZW5ndGhzIDwtIGdlbmVfbGVuZ3Roc1tyb3duYW1lcyhyYXdjb3VudHMpXQoKIyBNYWtlIERHRUxpc3Qgb2JqZWN0IGZvciBlZGdlUgpkZ2UgPC0gREdFTGlzdChjb3VudHMgPSByYXdjb3VudHMpCgojIENhbGN1bGF0ZSBSUEtNIChyZWFkcyBwZXIga2lsb2Jhc2UgcGVyIG1pbGxpb24pCnJwa20gPC0gcnBrbShkZ2UsIGdlbmUubGVuZ3RoID0gZ2VuZV9sZW5ndGhzKQoKIyBXcmFwIFJQS00gaW4gYW4gZXhwZXJpbWVudCBvYmplY3QgdG9vCmV4cHRfcnBrbSA8LSBjcmVhdGVfZXhwdChjb3VudF9kYXRhZnJhbWUgPSBycGttLAogICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm8gPSBnZmZfYW5ub3QpCgojIGxvZzIgdHJhbnNmb3JtIHRoZSBSUEtNIChhZ2Fpbiwgbm8gbm9ybWFsaXphdGlvbiBiZXlvbmQgbG9nKQpycGttX25vcm1hbGl6ZWRfZXhwIDwtIG5vcm1hbGl6ZV9leHB0KGV4cHRfcnBrbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInJhdyIpCgojIEdldCB0aGUgYWN0dWFsIGV4cHJlc3Npb24gbWF0cmljZXMgZnJvbSB0aGUgZXhwZXJpbWVudCBvYmplY3RzCnJwa20gPC0gZXhwcnMocnBrbV9ub3JtYWxpemVkX2V4cCkKY3BtIDwtIGV4cHJzKGNwbV9ub3JtYWxpemVkX2V4cCkKCiMgTWVyZ2UgQ1BNIGFuZCBSUEtNIG1hdHJpY2VzIHdpdGggZ2VuZSBhbm5vdGF0aW9uIGluZm8KY3BtX2Fubm90YXRlZCA8LSBtZXJnZShnZmZfYW5ub3QsIGNwbSwgYnkgPSAwKQpycGttX2Fubm90YXRlZCA8LSBtZXJnZShnZmZfYW5ub3QsIHJwa20sIGJ5ID0gMCkKYGBgCgojIyBIZWF0bWFwIG9mIGFsZ2luYXRlIGdlbmVzClRoaXMgZ2VuZXJhdGVzIGEgc21hbGwgaGVhdG1hcCBvZiB0aGUgYWxnaW5hdGUgZ2VuZXMgYWNyb3NzIHNhbXBsZXMgdG8gdmlzdWFsaXplIGV4cHJlc3Npb24uCgpgYGB7ciBoZWF0bWFwc30KIyBMb29wIHRocm91Z2ggQ1BNIGFuZCBSUEtNIHRvIHBsb3QgYm90aCBoZWF0bWFwcwpmb3IgKHR5cGUgaW4gYygiY3BtIiwgInJwa20iKSkgewogIAogICMgRGVmaW5lIGdlbmUgbGlzdAogIGFsZ19vcGVyb25fZ2VuZXMgPC0gYygKICAgICJhbGdBIiwgImFsZ0YiLCAiYWxnSiIsICJhbGdJIiwgImFsZ0wiLCAiYWxnWCIsICJhbGdHIiwgImFsZ0UiLAogICAgImFsZ0siLCAiYWxnNDQiLCAiYWxnOCIsICJhbGdEIiwgIm11Y0MiLCAibXVjQiIsICJhbGdVIiwgImFsZ1ciLAogICAgImFsZ1AiLCAiYWxnUSIsICJhbGdSIiwgImFsZ1oiLCAiYWxnQyIsICJhbGdCIgogICkKCiAgIyBHZXQgdGhlIHJpZ2h0IGRhdGEgcGVyIHR5cGUgb2YgdHJhbnNmb3JtYXRpb24KICBkYXRhX2Fubm90IDwtIGdldChwYXN0ZTAodHlwZSwgIl9hbm5vdGF0ZWQiKSkKICAKICAjIEZpeCByb3duYW1lcyB1c2luZyBnZW5lIG5hbWUgKG1ha2UgdW5pcXVlKQogIHJvd25hbWVzKGRhdGFfYW5ub3QpIDwtIG1ha2UubmFtZXMoZGF0YV9hbm5vdCRuYW1lLCB1bmlxdWUgPSBUUlVFKQogIAogICMgRHJvcCB1bmRlc2lyZWQgbWV0YWRhdGEgY29sdW1ucwogIGNvbHNfdG9fZXhjbHVkZSA8LSBjKCJSb3cubmFtZXMiLCJzZXFuYW1lcyIsInN0YXJ0IiwiZW5kIiwid2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICJzdHJhbmQiLCJzb3VyY2UiLCJ0eXBlIiwic2NvcmUiLCJwaGFzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgImdlbmVfaWQiLCJOYW1lIiwiRGJ4cmVmIiwiQWxpYXMiLCJuYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAiUGFyZW50IiwibG9jdXMiKQogIGtlZXAgPC0gIW5hbWVzKGRhdGFfYW5ub3QpICVpbiUgY29sc190b19leGNsdWRlCiAgZXhwcl9kYXRhIDwtIGRhdGFfYW5ub3RbLCBrZWVwXQogIAogICMgRXh0cmFjdCBtYXRyaXggZm9yIGFsZyBnZW5lcwogIGFsZ19nZW5lcyA8LSBleHByX2RhdGFbYWxnX29wZXJvbl9nZW5lcywgLCBkcm9wID0gRkFMU0VdCiAgbWF0IDwtIGFsZ19nZW5lcyAtIHJvd01lYW5zKGFsZ19nZW5lcykKICAKICAjIFB1bGwgc2FtcGxlIGFubm90YXRpb25zCiAgYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1ldGFkYXRhWywgYygiY29uZGl0aW9uIiwgImluZHVjZWQiKV0pCiAgY29sbmFtZXMoYW5ubykgPC0gYygiQ29uZGl0aW9uIiwgIkluZHVjZWQiKQogIAogICMgQ29sb3Igc2V0dGluZ3MgZm9yIGFubm90YXRpb24KICMgYW5uX2NvbG9ycyA8LSBsaXN0KAogIyAgQ29uZGl0aW9uID0gYygiTEItRE1TTyIgPSAiI0Q5NUYwMiIsICJMQi1JUFRHIiA9ICIjNjZBNjFFIiksCiAjICBJbmR1Y2VkID0gYygibm8iID0gImxpZ2h0Z3JleSIsICJ5ZXMiID0gImdyYXkyNyIpCiAjICkKICAKICAjIFNjYWxlIGRhdGEgYnkgcm93IChaLXNjb3JlIHBlciBnZW5lKQogIHNjYWxlZF9tYXQgPC0gdChzY2FsZSh0KG1hdCkpKQoKICAjIEJ1aWxkIGhlYXRtYXAKICBodCA8LSBIZWF0bWFwKAogICAgc2NhbGVkX21hdCwKICAgIG5hbWUgPSAiWi1zY29yZSIsCiAgICB0b3BfYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gYW5ubyMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY29sID0gYW5uX2NvbG9ycwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsCiAgICByb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwKICAgIGNvbHVtbl9uYW1lc19zaWRlID0gImJvdHRvbSIsCiAgICBjb2x1bW5fbmFtZXNfcm90ID0gNDUsCiAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSwKICAgIHNob3dfcm93X2RlbmQgPSBUUlVFLAogICAgc2hvd19jb2x1bW5fZGVuZCA9IFRSVUUKICApCiAgCiAgIyBEcmF3IGFuZCBzYXZlCiAgZHJhdyhodCkKICAKICBjYWlyb19wZGYocGFzdGUwKFN5cy5EYXRlKCksICJfYWxnX2hlYXRtYXBfIiwgdHlwZSwgIl8iLCBleHAsICJfIiwgdHJlYXRtZW50LCAiLnZzLiIsIGNvbnRyb2wsICIucGRmIikpCiAgZHJhdyhodCkKICBkZXYub2ZmKCkKfQoKYGBgCgojIERFU2VxCmBgYHtyIERFU2VxfQojIENyZWF0ZSBERVNlcURhdGFTZXQKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoCiAgY291bnREYXRhID0gcmF3Y291bnRzLAogIGNvbERhdGEgPSBtZXRhZGF0YSwKICBkZXNpZ24gPSBkZXNpZ25fZm9ybXVsYQopCgojIENoZWNrIG51bWJlciBvZiBnZW5lcyBiZWZvcmUgZmlsdGVyaW5nCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgYmVmb3JlIGZpbHRlcmluZzoiKQpucm93KGRkcykKCiMgRmlsdGVyOiBrZWVwIGdlbmVzIHdpdGggY291bnRzID49MTAgaW4gYXQgbGVhc3QgMiBzYW1wbGVzCnByaW50KCJGaWx0ZXJpbmcgZ2VuZXMgd2l0aCBjb3VudHMgPj0xMCBpbiBhdCBsZWFzdCAyIHNhbXBsZXMiKQprZWVwIDwtIHJvd1N1bXMoY291bnRzKGRkcykgPj0gMTApID49IDIgCmRkc19maWx0ZXJlZCA8LSBkZHNba2VlcCwgXQoKIyBDaGVjayBudW1iZXIgb2YgZ2VuZXMgYWZ0ZXIgZmlsdGVyaW5nCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgYWZ0ZXIgZmlsdGVyaW5nOiIpCm5yb3coZGRzX2ZpbHRlcmVkKQoKIyBSdW4gREVTZXEgb24gdGhlIGZpbHRlcmVkIGRhdGFzZXQKZGRzX2ZpbmFsIDwtIERFU2VxKGRkc19maWx0ZXJlZCkKCiMgU2hvdyBhdmFpbGFibGUgcmVzdWx0cwpyZXN1bHRzTmFtZXMoZGRzX2ZpbmFsKQoKIyBQbG90IGRpc3BlcnNpb24gZXN0aW1hdGVzCnBsb3REaXNwRXN0cyhkZHNfZmluYWwpCmBgYAoKIyBTYXZlIERFIHRhYmxlcyAKYGBge3Igc2F2ZV90YWJsZXN9CnJlcyA8LSByZXN1bHRzKGRkc19maW5hbCwgY29udHJhc3QgPSBjKCJleHBfNyIsICJ0cmVhdG1lbnQiLCAiY29udHJvbCIpKQpyZXNkZiA8LSBhcy5kYXRhLmZyYW1lKHJlcykKcmVzZGYkZ2VuZV9pZCA8LSByb3duYW1lcyhyZXNkZikKCmNwbSA8LSBhcy5kYXRhLmZyYW1lKGNwbSkKcnBrbSA8LSBhcy5kYXRhLmZyYW1lKHJwa20pCgojIGFwcGVuZCB0eXBlIG9mIHZhbHVlIHRvIHRoZSBkYXRhZnJhbWUgICAKY29sbmFtZXMocnBrbSkgPC0gcGFzdGUwKGNvbG5hbWVzKHJwa20pLCAiX3Jwa20iKQpjb2xuYW1lcyhjcG0pIDwtIHBhc3RlMChjb2xuYW1lcyhjcG0pLCAiX2NwbSIpCnJhd2NvdW50czIgPC0gcmF3Y291bnRzCmNvbG5hbWVzKHJhd2NvdW50czIpIDwtIHBhc3RlMChjb2xuYW1lcyhyYXdjb3VudHMyKSwgIl9yYXdjb3VudHMiKQoKIyBlbnN1cmUgY29sdW1uIGdlbmVfaWQgaXMgdGhlcmUKcnBrbSRnZW5lX2lkIDwtIHJvd25hbWVzKHJwa20pCmNwbSRnZW5lX2lkIDwtIHJvd25hbWVzKGNwbSkKcmF3Y291bnRzMiRnZW5lX2lkIDwtIHJvd25hbWVzKHJhd2NvdW50czIpCgpnZmZfYW5ub3QgPC0gZ2ZmX2Fubm90W3Jvd25hbWVzKHJlc2RmKSxdCgpkaW0ocmVzZGYpCiMgbWVyZ2Ugd2l0aCBzaWdnZW5lcwpyZXNkZiA8LSBmdWxsX2pvaW4ocmVzZGYsIGdmZl9hbm5vdCwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKaGVhZChyZXNkZikKCnBhX2dvIDwtIHJlYWQuY3N2KCIuLi8uLi9yYXctZGF0YS8yMDg5NjNfbWljcm9iZXMub25saW5lLmNzdiIsIGhlYWRlciA9IFRSVUUpCmhlYWQocGFfZ28pCgpjb2xfdG9fcmVtb3ZlIDwtIGludGVyc2VjdChjb2xuYW1lcyhwYV9nbyksY29sbmFtZXMocmVzZGYpKQpjb2xfdG9fcmVtb3ZlIDwtIHNldGRpZmYoY29sX3RvX3JlbW92ZSwgIkFsaWFzIikgIyByZXR1cm5zIGFsbCBleGNlcHQgdGhlIHNlY29uZCB2ZWN0b3IKCnBhX2dvIDwtIHBhX2dvICU+JSBzZWxlY3QoLWFsbF9vZihjb2xfdG9fcmVtb3ZlKSkKCnJlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcnBrbSwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKcmVzZGYgPC0gZnVsbF9qb2luKHJlc2RmLCBjcG0sIGJ5ID0gImdlbmVfaWQiLCBjb3B5ID0gRkFMU0UpCnJlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcmF3Y291bnRzMiwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKI3Jlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcGFfZ28sIGJ5ID0gIkFsaWFzIiwgY29weSA9IEZBTFNFKQpyZXNkZiA8LSBtZXJnZShyZXNkZiwgcGFfZ28sIGJ5ID0gIkFsaWFzIiwgY29weSA9IEZBTFNFKQoKaGVhZChyZXNkZikKd3JpdGUuY3N2KHJlc2RmLCBwYXN0ZTAoU3lzLkRhdGUoKSAsICJfcmVzdWx0c18iLGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgU2F2ZSBERUcgbGlzdApgYGB7ciBzYXZlX2RlZ30KIyBmaWx0ZXIgZm9yIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIChMRkMgPj0gMywgcGFkaiA8IHB2YWxfY3V0b2ZmKQpkaW0ocmVzZGYpCmhlYWQocmVzZGYpCgpzdW1tYXJ5KGlzLm5hKHJlc2RmJGxvZzJGb2xkQ2hhbmdlKSkKc3VtbWFyeShpcy5uYShyZXNkZiRwYWRqKSkKCnNpZ19nZW5lcyA8LSByZXNkZlthYnMocmVzZGYkbG9nMkZvbGRDaGFuZ2UpID49IGxvZ2ZjX2N1dG9mZiAmIHJlc2RmJHBhZGogPCBwdmFsX2N1dG9mZiwgXSAgJT4lIGRyb3BfbmEobG9nMkZvbGRDaGFuZ2UpCnNpZ19nZW5lcyRkaXJlY3Rpb24gPC0gaWZlbHNlKHNpZ19nZW5lcyRsb2cyRm9sZENoYW5nZSA+IDAsICJ1cCIsICJkb3duIikKCnN1bW1hcnkoaXMubmEoc2lnX2dlbmVzJGxvZzJGb2xkQ2hhbmdlKSkKc3VtbWFyeShpcy5uYShzaWdfZ2VuZXMkcGFkaikpCgpkaW0oc2lnX2dlbmVzKQpoZWFkKHNpZ19nZW5lcykKd3JpdGUuY3N2KHNpZ19nZW5lcywgcGFzdGUwKFN5cy5EYXRlKCksIl9zaWduaWZpY2FudGdlbmVzXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgUENBIHBsb3QgCmBgYHtyIFBDQX0KdnN0IDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gcmF3Y291bnRzLCBjb2xEYXRhID0gbWV0YWRhdGEsIGRlc2lnbiA9IH4gZXhwXzcgKyBiYXRjaCkKCiMgVmFyaWFuY2Ugc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb25zCnZzZCA8LSB2c3QodnN0LCBibGluZCA9IFRSVUUpCgojIFBDQSBwbG90CnBjYURhdGEgPC0gcGxvdFBDQSh2c2QsIGludGdyb3VwID0gYygiZXhwXzciLCAiYmF0Y2giLCAiY29uZGl0aW9uIiksIHJldHVybkRhdGEgPSBUUlVFKQpwZXJjZW50VmFyIDwtIHJvdW5kKDEwMCAqIGF0dHIocGNhRGF0YSwgInBlcmNlbnRWYXIiKSkKCiMgQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIGFic29sdXRlIHZhbHVlIGFtb25nIFBDMSBhbmQgUEMyCm1heF9hYnNfdmFsIDwtIG1heChjKGFicyhtaW4ocGNhRGF0YSRQQzEpKSwgYWJzKG1pbihwY2FEYXRhJFBDMikpLCBhYnMobWF4KHBjYURhdGEkUEMxKSksIGFicyhtYXgocGNhRGF0YSRQQzIpKSkpCgpheGlzX3NpemUgPC0gMTAKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiQXJpYWwiKSkKCnBjYSA8LSBnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBjb2xvciA9IGNvbmRpdGlvbiwgc2hhcGUgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyWzJdLCAiJSB2YXJpYW5jZSIpKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2KSkgKwogIGNvb3JkX2ZpeGVkKHJhdGlvID0gMSwgeGxpbSA9IGMoLW1heF9hYnNfdmFsLCBtYXhfYWJzX3ZhbCksIHlsaW0gPSBjKC1tYXhfYWJzX3ZhbCwgbWF4X2Fic192YWwpKSArCiAgbGFicyhjb2xvciA9ICJjb25kaXRpb24iLCBzaGFwZSA9ICJjb25kaXRpb24iKSArCiAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkNvbmRpdGlvbiIpLCAgIyBBZGp1c3Qgc2l6ZSBvZiBzaGFwZSBsZWdlbmQKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkNvbmRpdGlvbiIpKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gYXhpc19zaXplKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yKSwKICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMCwgY29sb3IgPSAiYmxhY2siKSwgICMgU2V0IHRoZSBheGlzIGxpbmUgbGluZXdpZHRoCiAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSksICAjIFNldCB0aGUgcGFuZWwgYm9yZGVyIGxpbmV3aWR0aAogIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpICAjIFNldCBsZWdlbmQga2V5IGJhY2tncm91bmQgdG8gd2hpdGUgYW5kIHJlbW92ZSBib3JkZXIKICApCgpwcmludChwY2EpCgpjYWlyb19wZGYocGFzdGUwKFN5cy5EYXRlKCksIl9wY2FfIixleHAsICJfIiwgdHJlYXRtZW50LCIudnMuIiwgY29udHJvbCwiLnBkZiIsIHNlcCA9ICIiKSkKcGNhCmRldi5vZmYoKQoKYGBgCgojIFZvbGNhbm8gcGxvdApgYGB7ciB2b2xjYW5vfQpzZXF1ZW5jZSA8LSBjKCJ0cmVhdG1lbnQiKQoKZm9yIChpIGluIHNlcXVlbmNlKSB7CiAgICBzZXQuc2VlZCgwKQogICAgcmVzIDwtIHJlc3VsdHMoZGRzX2ZpbmFsLCBjb250cmFzdCA9IGMoImV4cF83IiwgaSwgImNvbnRyb2wiKSkKCiAgZ3AyIDwtIHdlc19wYWxldHRlcyRaaXNzb3UxCiAga2V5IDwtIHJlYWQuY3N2KCIuLi8uLi9yYXctZGF0YS9wYTE0X2dlbmVfa2V5LmNzdiIsICBoZWFkZXIgPSBUUlVFKQoKICByb3duYW1lcyhrZXkpIDwtIGtleSRnZW5lX2lkCgogIHJlcyA8LSBtZXJnZShrZXksIGFzLmRhdGEuZnJhbWUocmVzKSwgYnk9MCkKICByZXMgPC0gYXMuZGF0YS5mcmFtZShyZXMpCiAgcmVzJEFsaWFzIDwtIHJvd25hbWVzKHJlcykKCiAjIERlZmluZSBnZW5lIGxpc3QKICBhbGdfZ2VuZXMgPC0gYygKICAgICJhbGdBIiwgImFsZ0YiLCAiYWxnSiIsICJhbGdJIiwgImFsZ0wiLCAiYWxnWCIsICJhbGdHIiwgImFsZ0UiLAogICAgImFsZ0siLCAiYWxnNDQiLCAiYWxnOCIsICJhbGdEIiwgIm11Y0MiLCAibXVjQiIsICJhbGdVIiwgImFsZ1ciLAogICAgImFsZ1AiLCAiYWxnUSIsICJhbGdSIiwgImFsZ1oiLCAiYWxnQyIsICJhbGdCIgogICkKCmxvZ2ZjX2N1dG9mZgprZXl2YWxzIDwtIGlmZWxzZSgKIHJlcyRsb2cyRm9sZENoYW5nZSA8PSAtbG9nZmNfY3V0b2ZmICYgcmVzJHBhZGogPD0gcHZhbF9jdXRvZmYsIGdwMlsxXSwKICBpZmVsc2UocmVzJGxvZzJGb2xkQ2hhbmdlID49IGxvZ2ZjX2N1dG9mZiAmIHJlcyRwYWRqIDw9IHB2YWxfY3V0b2ZmLCBncDJbNV0sCiAgICAgICAgICdsaWdodGdyZXknKSkKa2V5dmFsc1tpcy5uYShrZXl2YWxzKV0gPC0gJ2xpZ2h0Z3JleScKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSBncDJbNV1dIDwtICdVcC1yZWd1bGF0ZWQnCm5hbWVzKGtleXZhbHMpW2tleXZhbHMgPT0gJ2xpZ2h0Z3JleSddIDwtICdOUycKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSBncDJbMV1dIDwtICdEb3duLXJlZ3VsYXRlZCcKCnZvbGNhbm8gPC0gRW5oYW5jZWRWb2xjYW5vKHJlcywKICAgICAgICAgICAgICAgICAgICAgbGFiID0gcmVzW1sibmFtZSJdXSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gYWxnX2dlbmVzLAogICAgICAgICAgICAgICAgICAgICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywKICAgICAgICAgICAgICAgICAgICAgeSA9ICdwYWRqJywKICAgICAgICAgICAgICAgICAgICAgeGxhYiA9IGJxdW90ZSh+TG9nWzJdfiAnZm9sZCBjaGFuZ2UnKSwKICAgICAgICAgICAgICAgICAgICAgcEN1dG9mZiA9IHB2YWxfY3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IGxvZ2ZjX2N1dG9mZiwKICAgICAgICAgICAgICAgICAgICAgY3V0b2ZmTGluZVR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMSwKICAgICAgICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDMuMCwKICAgICAgICAgICAgICAgICAgICAgYXhpc0xhYlNpemUgPSAxNCwKICAgICAgICAgICAgICAgICAgICAgbGFiQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgICAgICAgbGFiRmFjZSA9ICdib2xkJywKICAgICAgICAgICAgICAgICAgICAgI2NvbCA9IGMoJ2dyZXknLCBncDJbMl0sIGdwMlszXSwgZ3AyWzFdKSwKICAgICAgICAgICAgICAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscywKICAgICAgICAgICAgICAgICAgICAgY29sQWxwaGEgPSA1LzUsCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZExhYlNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgICAgICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgYXJyb3doZWFkcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgIGdyaWRsaW5lcy5tYWpvciA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICBib3JkZXJXaWR0aCA9IDAuMywKICAgICAgICAgICAgICAgICAgICAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKHRyZWF0bWVudCwiIHZzICIsIGNvbnRyb2wsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgI2NhcHRpb24gPSBwYXN0ZTAoInRvdGFsID0gIiwgbnJvdyh0b3B0YWJsZSksICIgdmFyaWFibGVzIiksCiAgICAgICAgICAgICAgICAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIlZvbGNhbm8gcGxvdCB3aXRoIGxvZzIgRkMgb2YgIiwgbG9nZmNfY3V0b2ZmLCIgYW5kIFAgdmFsdWUgb2YgIixwdmFsX2N1dG9mZiwgIi4iKSwKICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICN5bGltID0gYygwLDEwKSwKICAgICAgICAgICAgICAgICAgICAgY29sQ29ubmVjdG9ycyA9ICdibGFjaycpICsgCiAgICAgIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9MC4yKSkgIyArCiAjIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKC01LCAtMi41LCAwLCAyLjUsIDUpLCBsaW1pdHMgPSBjKC02LDYpKQoKcHJpbnQodm9sY2FubykKCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwiX3ZvbGNhbm9fIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwiLnZzLiIsIGNvbnRyb2wsIi5wZGYiLCBzZXAgPSAiIikpCnByaW50KHZvbGNhbm8pCmRldi5vZmYoKQp9CgpgYGAKCiMgTUEgcGxvdApgYGB7ciBNQV9wbG90fQpzZXF1ZW5jZSA8LSBjKCJ0cmVhdG1lbnQiKQoKZm9yIChpIGluIHNlcXVlbmNlKSB7CiAgICBzZXQuc2VlZCgwKQoKcmVzIDwtIHJlc3VsdHMoZGRzX2ZpbmFsLCBjb250cmFzdCA9IGMoImV4cF83IiwgaSwgImNvbnRyb2wiKSkKCmdwMiA8LSB3ZXNfcGFsZXR0ZXMkWmlzc291MQoKcmVzJGdlbmVfaWQgPC0gcm93bmFtZXMocmVzKQpyZXMgPC0gYXMuZGF0YS5mcmFtZShyZXMpCmhlYWQocmVzKQpyZXMgPC0gZnVsbF9qb2luKGtleSwgYXMuZGF0YS5mcmFtZShyZXMpLCBieT0iZ2VuZV9pZCIpCnJvd25hbWVzKHJlcykgPC0gcmVzJEFsaWFzCgphbnkoaXMubmEocmVzKSkgICMgQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBOQXMKCnJlcyA8LSByZXMgJT4lIGZpbHRlcighaXMubmEoYmFzZU1lYW4pKQoKCm1hIDwtIGdnbWFwbG90KHJlcywgCiAgICAgICAgICAgICAgIGZkciA9IHB2YWxfY3V0b2ZmLCAKICAgICAgICAgICAgICAgZmMgPSAyXihsb2dmY19jdXRvZmYpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IDEsCiAgICAgICAgICAgICAgIHBhbGV0dGUgPSBjKChncDJbNV0pLCAoZ3AyWzFdKSksCiAgICAgICAgICAgICAgIHNlbGVjdC50b3AubWV0aG9kID0gImZjIiwKICAgICAgICAgICAgICMgIHlsaW0gPSBjKC0xNSwxNSksCiAgICAgICAgICAgICAgIGxlZ2VuZCA9ICJib3R0b20iLCAKICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZTAodHJlYXRtZW50LCIgdnMgIiwgY29udHJvbCwgc2VwID0gIiIpLAogICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJWb2xjYW5vIHBsb3Qgd2l0aCBsb2cyIEZDIG9mICIsIGxvZ2ZjX2N1dG9mZiwiIGFuZCBQIHZhbHVlIG9mICIscHZhbF9jdXRvZmYsICIuIiksCiAgICAgICAgICAgICAgIGZvbnQubGFiZWwgPSBjKCAxMiksIAogICAgICAgICAgICAgbGFiZWwucmVjdGFuZ2xlID0gRkFMU0UsCiAgICAgICAgICAgICAgZ2VuZW5hbWVzID0gcmVzJG5hbWUsCiAgICAgICAgICAgICAgZm9udC5sZWdlbmQgPSBjKDEyKSwKICAgICAgICAgICAgICAgZm9udC5tYWluID0gYygiYm9sZCIsIDE0KSwKICAgICAgICAgICAgICAgYWxwaGEgPSAxLjUsCiAgICAgICAgICAgICAgIGdndGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkID1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSkpIApwcmludChtYSkKCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwiX21hXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIucGRmIikpCnByaW50KG1hKQpkZXYub2ZmKCkKfQpgYGAKCg==