1 Overview

batch condition media treatment induced exp_1
SK061 1 LB-DMSO LB DMSO no control
SK062 2 LB-DMSO LB DMSO no control
SK063 3 LB-DMSO LB DMSO no control
SK064 1 LB-IPTG LB DMSO yes treatment
SK065 2 LB-IPTG LB DMSO yes treatment
SK066 3 LB-IPTG LB DMSO yes treatment

2 Project variables

##       batch condition media treatment induced     exp_1
## SK061     1   LB-DMSO    LB      DMSO      no   control
## SK062     2   LB-DMSO    LB      DMSO      no   control
## SK063     3   LB-DMSO    LB      DMSO      no   control
## SK064     1   LB-IPTG    LB      DMSO     yes treatment
## SK065     2   LB-IPTG    LB      DMSO     yes treatment
## SK066     3   LB-IPTG    LB      DMSO     yes treatment
## [1] "The control is: LB-DMSO"
## [1] "The treatment is: LB-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_1 + 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)
##             SK061 SK062 SK063 SK064 SK065 SK066
## gene1650835  1555  1680  1858  2234  2528  1719
## gene1650837  1560  1390  1898  1266  1754  1368
## gene1650839   558   436   675   722   770   657
## gene1650841  2492  2352  2588  3671  4307  3347
## gene1650843   285   247   296   436   435   313
## gene1650845   129   106   145   257   299   177
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 276 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 276 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] 5755
# 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_1_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_1", "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] 5755    7
# merge with siggenes
resdf <- full_join(resdf, gff_annot, by = "gene_id", copy = FALSE)
head(resdf)
##    baseMean log2FoldChange     lfcSE      stat      pvalue        padj
## 1 1889.0134      0.1827247 0.1661648  1.099659 0.271480691 0.352044023
## 2 1524.5481     -0.2964195 0.1661966 -1.783548 0.074497188 0.116477449
## 3  624.3261      0.2334435 0.1809096  1.290388 0.196916028 0.270788947
## 4 3056.7807      0.4503432 0.1561946  2.883219 0.003936333 0.008282851
## 5  326.9441      0.3534568 0.2044740  1.728615 0.083878091 0.129276490
## 6  178.2316      0.7758608 0.2492374  3.112939 0.001852345 0.004117515
##       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 1889.0134      0.1827247 0.1661648  1.099659 0.271480691
## 2 PA14_00020 1524.5481     -0.2964195 0.1661966 -1.783548 0.074497188
## 3 PA14_00030  624.3261      0.2334435 0.1809096  1.290388 0.196916028
## 4 PA14_00050 3056.7807      0.4503432 0.1561946  2.883219 0.003936333
## 5 PA14_00060  326.9441      0.3534568 0.2044740  1.728615 0.083878091
## 6 PA14_00070  178.2316      0.7758608 0.2492374  3.112939 0.001852345
##          padj     gene_id   seqnames start  end width strand    source type
## 1 0.352044023 gene1650835 chromosome   483 2027  1545      + PseudoCAP gene
## 2 0.116477449 gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene
## 3 0.270788947 gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene
## 4 0.008282851 gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene
## 5 0.129276490 gene1650843 chromosome  7018 7791   774      - PseudoCAP gene
## 6 0.004117515 gene1650845 chromosome  7803 8339   537      - PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK061_rpkm SK062_rpkm
## 1    NA     0      GeneID:4384099       dnaA         <NA>   7.915314   8.117840
## 2    NA     0      GeneID:4384100       dnaN         <NA>   8.403091   8.328621
## 3    NA     0      GeneID:4384101       recF         <NA>   6.919760   6.657980
## 4    NA     0      GeneID:4384102       gyrB         <NA>   7.947574   7.955889
## 5    NA     0      GeneID:4385186 PA14_00060         <NA>   6.474956   6.361612
## 6    NA     0      GeneID:4385187 PA14_00070         <NA>   5.867393   5.679355
##   SK063_rpkm SK064_rpkm SK065_rpkm SK066_rpkm SK061_cpm SK062_cpm SK063_cpm
## 1   8.104660   8.176179   8.165287   7.893669  8.540811  8.743613  8.730417
## 2   8.618680   7.842995   8.122956   8.048415  8.545430  8.470939  8.761074
## 3   7.126030   7.029755   6.934080   6.988440  7.069138  6.807123  7.275566
## 4   7.935406   8.244496   8.285574   8.205787  9.219743  9.228078  9.207545
## 5   6.462976   6.823946   6.633153   6.444121  6.110090  5.997131  6.098149
## 6   5.967636   6.591050   6.619830   6.152874  4.991538  4.806420  5.090371
##   SK064_cpm SK065_cpm SK066_cpm SK061_rawcounts SK062_rawcounts SK063_rawcounts
## 1  8.802026  8.791120  8.519135            1555            1680            1858
## 2  7.985143  8.265208  8.190642            1560            1390            1898
## 3  7.179220  7.083470  7.137873             558             436             675
## 4  9.517304  9.558461  9.478520            2492            2352            2588
## 5  6.458065  6.267796  6.079357             285             247             296
## 6  5.706889  5.735417  5.273245             129             106             145
##   SK064_rawcounts SK065_rawcounts SK066_rawcounts locusId   accession        GI
## 1            2234            2528            1719 2194572 YP_788156.1 116053721
## 2            1266            1754            1368 2194573 YP_788157.1 116053722
## 3             722             770             657 2194574 YP_788158.1 116053723
## 4            3671            4307            3347 2194575 YP_788159.1 116053724
## 5             436             435             313 2194576 YP_788160.1 116053725
## 6             257             299             177 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] 5748   54
head(resdf)
##        Alias  baseMean log2FoldChange     lfcSE      stat      pvalue
## 1 PA14_00010 1889.0134      0.1827247 0.1661648  1.099659 0.271480691
## 2 PA14_00020 1524.5481     -0.2964195 0.1661966 -1.783548 0.074497188
## 3 PA14_00030  624.3261      0.2334435 0.1809096  1.290388 0.196916028
## 4 PA14_00050 3056.7807      0.4503432 0.1561946  2.883219 0.003936333
## 5 PA14_00060  326.9441      0.3534568 0.2044740  1.728615 0.083878091
## 6 PA14_00070  178.2316      0.7758608 0.2492374  3.112939 0.001852345
##          padj     gene_id   seqnames start  end width strand    source type
## 1 0.352044023 gene1650835 chromosome   483 2027  1545      + PseudoCAP gene
## 2 0.116477449 gene1650837 chromosome  2056 3159  1104      + PseudoCAP gene
## 3 0.270788947 gene1650839 chromosome  3169 4278  1110      + PseudoCAP gene
## 4 0.008282851 gene1650841 chromosome  4275 6695  2421      + PseudoCAP gene
## 5 0.129276490 gene1650843 chromosome  7018 7791   774      - PseudoCAP gene
## 6 0.004117515 gene1650845 chromosome  7803 8339   537      - PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK061_rpkm SK062_rpkm
## 1    NA     0      GeneID:4384099       dnaA         <NA>   7.915314   8.117840
## 2    NA     0      GeneID:4384100       dnaN         <NA>   8.403091   8.328621
## 3    NA     0      GeneID:4384101       recF         <NA>   6.919760   6.657980
## 4    NA     0      GeneID:4384102       gyrB         <NA>   7.947574   7.955889
## 5    NA     0      GeneID:4385186 PA14_00060         <NA>   6.474956   6.361612
## 6    NA     0      GeneID:4385187 PA14_00070         <NA>   5.867393   5.679355
##   SK063_rpkm SK064_rpkm SK065_rpkm SK066_rpkm SK061_cpm SK062_cpm SK063_cpm
## 1   8.104660   8.176179   8.165287   7.893669  8.540811  8.743613  8.730417
## 2   8.618680   7.842995   8.122956   8.048415  8.545430  8.470939  8.761074
## 3   7.126030   7.029755   6.934080   6.988440  7.069138  6.807123  7.275566
## 4   7.935406   8.244496   8.285574   8.205787  9.219743  9.228078  9.207545
## 5   6.462976   6.823946   6.633153   6.444121  6.110090  5.997131  6.098149
## 6   5.967636   6.591050   6.619830   6.152874  4.991538  4.806420  5.090371
##   SK064_cpm SK065_cpm SK066_cpm SK061_rawcounts SK062_rawcounts SK063_rawcounts
## 1  8.802026  8.791120  8.519135            1555            1680            1858
## 2  7.985143  8.265208  8.190642            1560            1390            1898
## 3  7.179220  7.083470  7.137873             558             436             675
## 4  9.517304  9.558461  9.478520            2492            2352            2588
## 5  6.458065  6.267796  6.079357             285             247             296
## 6  5.706889  5.735417  5.273245             129             106             145
##   SK064_rawcounts SK065_rawcounts SK066_rawcounts locusId   accession        GI
## 1            2234            2528            1719 2194572 YP_788156.1 116053721
## 2            1266            1754            1368 2194573 YP_788157.1 116053722
## 3             722             770             657 2194574 YP_788158.1 116053723
## 4            3671            4307            3347 2194575 YP_788159.1 116053724
## 5             436             435             313 2194576 YP_788160.1 116053725
## 6             257             299             177 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    5748
summary(is.na(resdf$padj))
##    Mode   FALSE 
## logical    5748
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     835
summary(is.na(sig_genes$padj))
##    Mode   FALSE 
## logical     835
dim(sig_genes)
## [1] 835  55
head(sig_genes)
##        Alias   baseMean log2FoldChange     lfcSE       stat        pvalue
## 1 PA14_00080  619.54389      -3.097715 0.1942112 -15.950238  2.838116e-57
## 2 PA14_00570  233.90670       2.457137 0.2383140  10.310500  6.317187e-25
## 3 PA14_00590   60.51625       2.238070 0.3964416   5.645397  1.648008e-08
## 4 PA14_00600   34.41869      -2.040663 0.4805696  -4.246342  2.172889e-05
## 5 PA14_00620  342.37505      -3.488252 0.2330360 -14.968722  1.175591e-50
## 6 PA14_00630 1191.94492      -4.102565 0.1829507 -22.424429 2.273928e-111
##            padj     gene_id   seqnames start   end width strand    source type
## 1  1.349864e-55 gene1650847 chromosome  8671 10377  1707      + PseudoCAP gene
## 2  7.256569e-24 gene1650927 chromosome 59018 59704   687      + PseudoCAP gene
## 3  6.655638e-08 gene1650931 chromosome 60241 60750   510      + PseudoCAP gene
## 4  6.322030e-05 gene1650933 chromosome 60765 61148   384      - PseudoCAP gene
## 5  4.364854e-49 gene1650935 chromosome 61430 63091  1662      - PseudoCAP gene
## 6 7.270254e-109 gene1650937 chromosome 63701 63841   141      + PseudoCAP gene
##   score phase Name         Dbxref       name Parent locus SK061_rpkm SK062_rpkm
## 1    NA     0      GeneID:4385188 PA14_00080         <NA>   7.133086   7.356125
## 2    NA     0      GeneID:4381739 PA14_00570         <NA>   4.758961   4.771188
## 3    NA     0      GeneID:4381741 PA14_00590         <NA>   3.237308   3.085194
## 4    NA     0      GeneID:4381742 PA14_00600         <NA>   4.509128   5.462288
## 5    NA     0      GeneID:4381743 PA14_00620         <NA>   6.149557   6.609425
## 6    NA     0      GeneID:4381744 PA14_00630         <NA>  11.762289  11.911950
##   SK063_rpkm SK064_rpkm SK065_rpkm SK066_rpkm SK061_cpm SK062_cpm SK063_cpm
## 1   7.201252   4.107099   4.085597   3.996607  7.900286  8.123936  7.968649
## 2   4.409378   7.184945   6.920300   6.614281  4.241417  4.253442  3.898365
## 3   3.804062   5.339107   5.644514   5.121183  2.405847  2.268491  2.928602
## 4   5.147570   2.853934   3.337150   2.827207  3.226520  4.133028  3.830604
## 5   6.565614   2.948035   2.931187   3.075128  6.874360  7.336448  7.292455
## 6  11.852083   7.484965   7.639493   7.667280  8.938584  9.087996  9.028225
##   SK064_cpm SK065_cpm SK066_cpm SK061_rawcounts SK062_rawcounts SK063_rawcounts
## 1  4.843465  4.821429  4.730142             996            1092            1094
## 2  6.647838  6.384099  6.079357              75              71              61
## 3  4.401519  4.700530  4.189039              18              15              29
## 4  1.762222  2.168876  1.740385              35              65              58
## 5  3.604499  3.586729  3.738199             487             631             683
## 6  4.706979  4.856679  4.883650            2050            2134            2285
##   SK064_rawcounts SK065_rawcounts SK066_rawcounts locusId   accession        GI
## 1             139             156             120 2194578 YP_788162.1 116053727
## 2             498             472             313 2194618 YP_788202.1 116053767
## 3             101             143              81 2194620 YP_788204.1 116053769
## 4              12              20              11 2194621 YP_788205.1 116053770
## 5              56              63              58 2194622 YP_788206.1 116053771
## 6             126             160             134 2194623 YP_788207.1 116053772
##   scaffoldId  stop                                      desc     COG COGFun
## 1       4582 10377               hypothetical protein (NCBI)               
## 2       4582 59704               putative lipoprotein (NCBI) COG1462      M
## 3       4582 60750               putative lipoprotein (NCBI) COG4380      S
## 4       4582 60765 putative transcriptional regulator (NCBI)               
## 5       4582 61430               hypothetical protein (NCBI)               
## 6       4582 63841               hypothetical protein (NCBI)               
##                                                           COGDesc TIGRFam
## 1                                                                        
## 2 Uncharacterized protein involved in formation of curli polymers        
## 3                   Uncharacterized protein conserved in bacteria        
## 4                                                                        
## 5                                                                        
## 6                                                                        
##   TIGRRoles                                          GO EC ECDesc direction
## 1           GO:0006118,GO:0020037,GO:0005506,GO:0009055                down
## 2                                 GO:0015031,GO:0042597                  up
## 3                                            GO:0005975                  up
## 4                                            GO:0043565                down
## 5                                                                      down
## 6                                                                      down
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_1 + 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_1", "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_1", 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_1", 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()
}

LS0tCnRpdGxlOiAiMjAyNV9leHBfMV9hbGdpbmF0ZV9ERUciCmF1dGhvcjogIk5vdXIgRWwgSHVzc2VpbmkiCmRhdGU6ICIyMDI1IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IGZhbHNlICAjIEVuc3VyZXMgVE9DIGlzIGV4cGFuZGVkIGJ5IGRlZmF1bHQKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgdGhlbWU6CiAgICAgIGJvb3Rzd2F0Y2g6IHplcGh5cgogICAgY3NzOiBzdHlsZS5jc3MgICMgTGluayB0byB5b3VyIGN1c3RvbSBDU1MgZmlsZQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoImthYmxlRXh0cmEiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoImdnZm9yY2UiKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpsaWJyYXJ5KCJwaGVhdG1hcCIpCmxpYnJhcnkoIndlc2FuZGVyc29uIikKbGlicmFyeSgiRW5oYW5jZWRWb2xjYW5vIikKbGlicmFyeSgiZ2dwdWJyIikKbGlicmFyeSgiaHBnbHRvb2xzIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJ0aWJibGUiKSAKbGlicmFyeSgiZWRnZVIiKQpsaWJyYXJ5KCJnZW5lZmlsdGVyIikKbGlicmFyeSgicGhlYXRtYXAiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoIkNvbXBsZXhIZWF0bWFwIikKbGlicmFyeSgiZ29zZXEiKQpsaWJyYXJ5KCJwbHlyIikKbGlicmFyeSgiZ2VvbXRleHRwYXRoIikKYGBgCgojIE92ZXJ2aWV3CgpgYGB7ciBzYW1wbGVfdGFibGUsIGVjaG89RkFMU0V9CiMgTG9hZCBtZXRhZGF0YSBDU1YgZmlsZSBpbnRvIGEgZGF0YWZyYW1lLCB1c2luZyB0aGUgZmlyc3QgY29sdW1uIGFzIHJvdyBuYW1lcwptZXRhZGF0YSA8LSByZWFkLmNzdigiLi4vLi4vcmF3LWRhdGEvbWV0YWRhdGFfYWxnaW5hdGVfdnRsLmNzdiIsIHJvdy5uYW1lcyA9IDEsIGhlYWRlciA9IFRSVUUpCgojIEZpbHRlciB0aGUgZGF0YSB0byBpbmNsdWRlIG9ubHkgcm93cyB3aGVyZSBleHBfMSBpcyBlaXRoZXIgImNvbnRyb2wiIG9yICJ0cmVhdG1lbnQiCiMgVGhlbiByZW1vdmUgb3RoZXIgZXhwZXJpbWVudHMgKGV4cF8yIHRvIGV4cF82KQptZXRhZGF0YSA8LSBmaWx0ZXIobWV0YWRhdGEsIGV4cF8xICVpbiUgYygiY29udHJvbCIsICJ0cmVhdG1lbnQiKSkgJT4lCiAgICBzZWxlY3QoYmF0Y2gsIGNvbmRpdGlvbiwgbWVkaWEsIHRyZWF0bWVudCwgaW5kdWNlZCwgZXhwXzEpIAoKIyBEaXNwbGF5IHRoZSBjbGVhbmVkIG1ldGFkYXRhIHRhYmxlIHVzaW5nIGtuaXRyOjprYWJsZSBhbmQga2FibGVFeHRyYSBzdHlsaW5nCm1ldGFkYXRhICU+JQogIGtibCgpICU+JSAgIyBDcmVhdGUgYSBiYXNpYyB0YWJsZQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IFRSVUUpICAjIEFwcGx5IGEgY2xhc3NpYyB0YWJsZSBzdHlsZSB3aXRoIGZ1bGwgd2lkdGgKYGBgIAoKIyBQcm9qZWN0IHZhcmlhYmxlcwpgYGB7ciBwcm9qZWN0X3BhcmFtZXRlcnMsIGVjaG89RkFMU0V9CiMgRGVmaW5lIHRoZSBsYWJlbHMgZm9yIGNvbnRyb2wgYW5kIHRyZWF0bWVudCBncm91cHMgdXNlZCBpbiB0aGUgZXhwZXJpbWVudApoZWFkKG1ldGFkYXRhKQojIEV4dHJhY3QgY29udHJvbCBhbmQgdHJlYXRtZW50IGNvbmRpdGlvbnMgYmFzZWQgb24gYGV4cF8xYCBsYWJlbHMKY29udHJvbCA8LSBtZXRhZGF0YVttZXRhZGF0YSRleHBfMSA9PSAiY29udHJvbCIsIF0KdHJlYXRtZW50IDwtIG1ldGFkYXRhW21ldGFkYXRhJGV4cF8xID09ICJ0cmVhdG1lbnQiLCBdCgpjb250cm9sIDwtIHVuaXF1ZShjb250cm9sJGNvbmRpdGlvbikKdHJlYXRtZW50IDwtIHVuaXF1ZSh0cmVhdG1lbnQkY29uZGl0aW9uKQoKcHJpbnQocGFzdGUwKCJUaGUgY29udHJvbCBpczogIiwgY29udHJvbCkpCnByaW50KHBhc3RlMCgiVGhlIHRyZWF0bWVudCBpczogIiwgdHJlYXRtZW50KSkKCiMgU2V0IGRlZmF1bHQgdGV4dCBzaXplcyBmb3IgcGxvdHMKdGV4dC5zaXplIDwtIDEyICAgIApheGlzLnRleHQuc2l6ZSA8LSAxNAoKbG9nZmNfY3V0b2ZmIDwtIDIKcHZhbF9jdXRvZmYgPC0gMC4wMQoKIyBTZXQgdmFyaWFibGVzIGZvciB0aGUgcHJvamVjdCB1c2VkIGluIGZpbGVuYW1lcyBhbmQgcGxvdCB0aXRsZXMKcHJvamVjdCA8LSAib3JuX2FsZ2luYXRlX3JuYXNlcSIKZXhwIDwtICJleHBfMSIgICAgICAgICAgICAgICAgICAgIApgYGAKCmBgYHtyIHJhd2RhdGF9CiMgTG9hZCByYXcgY291bnQgZGF0YQpyYXdjb3VudHMgPC0gcmVhZC5jc3YoIi4uLy4uL3Jhdy1kYXRhL2h0c2VxX1NLX3VuZmlsdGVyZWRfcmV2ZXJzZV9zdHJhbmRfY291bnQuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLCBoZWFkZXIgPSBUUlVFKQoKIyBBcHBlbmQgYSBwcmVmaXggdG8gdGhlIGJhdGNoIGFuZCBydW4gY29sdW1ucyB0byB0dXJuIHRvIGNoYXJhY3RlciBjbGFzcwptZXRhZGF0YVtbImJhdGNoIl1dIDwtIHBhc3RlMCgiYiIsIG1ldGFkYXRhW1siYmF0Y2giXV0pCm1ldGFkYXRhW1sicnVuIl1dIDwtIHBhc3RlMCgiciIsIG1ldGFkYXRhW1sicnVuIl1dKQoKIyBTdWJzZXQgdGhlIHJhd2NvdW50cyBkYXRhZnJhbWUgdG8gb25seSBpbmNsdWRlIHNhbXBsZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBleHBlcmltZW50CnNhbXBsZXMgPC0gcm93bmFtZXMobWV0YWRhdGEpCnJhd2NvdW50cyA8LSBzZWxlY3QocmF3Y291bnRzLCBhbGxfb2Yoc2FtcGxlcykpCgojIEVuc3VyZSB0aGF0IHRoZSBvcmRlciBvZiBzYW1wbGVzIGluIG1ldGFkYXRhIG1hdGNoZXMgdGhlIG9yZGVyIG9mIGNvbHVtbnMgaW4gcmF3Y291bnRzCmFsbChyb3duYW1lcyhtZXRhZGF0YSkgPT0gY29sbmFtZXMocmF3Y291bnRzKSkgICMgU2hvdWxkIHJldHVybiBUUlVFIGlmIG9yZGVyIGlzIGNvcnJlY3QKCiMgRGVmaW5lIHRoZSBkZXNpZ24gZm9ybXVsYSBmb3IgREVTZXEyLCBpbmNsdWRpbmcgbWFpbiBjb25kaXRpb24gYW5kIGJhdGNoIGVmZmVjdApkZXNpZ25fZm9ybXVsYSA8LSB+IGV4cF8xICsgYmF0Y2gKCiMgQ3JlYXRlIERFU2VxMiBkYXRhc2V0IG9iamVjdCBmcm9tIHRoZSBmaWx0ZXJlZCBjb3VudCBtYXRyaXggYW5kIG1ldGFkYXRhCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KAogIGNvdW50RGF0YSA9IHJhd2NvdW50cywKICBjb2xEYXRhID0gbWV0YWRhdGEsCiAgZGVzaWduID0gZGVzaWduX2Zvcm11bGEKKQpgYGAKCgojIExpYnJhcnkgc2l6ZSBwZXIgc2FtcGxlCmBgYHtyIGxpYnJhcnlfc2l6ZX0KIyBTdW0gdXAgdGhlIGNvdW50cyBmb3IgZWFjaCBzYW1wbGUKcmF3Y291bnRzX3N1bXMgPC0gY29sU3VtcyhyYXdjb3VudHMpCgojIFR1cm4gaXQgaW50byBhIGRhdGEgZnJhbWUKZGF0YSA8LSBkYXRhLmZyYW1lKAogIENhdGVnb3J5ID0gbmFtZXMocmF3Y291bnRzX3N1bXMpLAogIENvdW50ID0gYXMubnVtZXJpYyhyYXdjb3VudHNfc3VtcykKKQoKIyBNYWtlIHN1cmUgc2FtcGxlIG9yZGVyIGlzIGNvbnNpc3RlbnQKZGF0YSA8LSBkYXRhICU+JQogIG11dGF0ZShDYXRlZ29yeSA9IGZhY3RvcihDYXRlZ29yeSwgbGV2ZWxzID0gc29ydCh1bmlxdWUoQ2F0ZWdvcnkpKSkpCgojIFBsb3QgYmFyIGNoYXJ0IG9mIGxpYnJhcnkgc2l6ZXMKcCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBDYXRlZ29yeSwgeSA9IENvdW50LCBmaWxsID0gQ2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAjIGNvb3JkX2ZsaXAoKSAjIGZsaXAgaWYgdG9vIG1hbnkgc2FtcGxlcyB0byByZWFkIGxhYmVscyBlYXNpbHkKICBsYWJzKHkgPSAiTGlicmFyeSBzaXplIChNKSIsIHggPSBOVUxMKSArICAjIHJlbW92ZSB4IGxhYmVsLCByZW5hbWUgeSBheGlzCiAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKyAgIyBvcHRpb25hbCBjb2xvciBwYWxldHRlCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoc2NhbGUgPSAxZS02KSwgICMgc2hvdyBjb3VudHMgaW4gbWlsbGlvbnMKICAgIGxpbWl0cyA9IGMoMCwgKG1heChkYXRhJENvdW50KSArIDFlNikpICAgICAgICAjIGFkZCBhIGJpdCBvZiBzcGFjZSBvbiB0b3AKICApICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LnNpemUsIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksICAjIHNsYW50IGxhYmVscwogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gYXhpcy50ZXh0LnNpemUpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRleHQuc2l6ZSksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAgIyBubyBsZWdlbmQgbmVlZGVkIHNpbmNlIGVhY2ggYmFyIGlzIGEgZGlmZmVyZW50IHNhbXBsZQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgU2hvdyB0aGUgcGxvdApwCgojIFNhdmUgdGhlIHBsb3QgYXMgYSBQREYgd2l0aCB0b2RheeKAmXMgZGF0ZSBhbmQgcHJvamVjdCBuYW1lCmdnc2F2ZShwYXN0ZTAoU3lzLkRhdGUoKSwgIl9saWJyYXJ5X3NpemVfIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwiLnZzLiIsIGNvbnRyb2wsICIucGRmIiksIGRldmljZSA9ICJwZGYiKQpgYGAKCiMgRXhwcmVzc2lvbiBkaXN0cmlidXRpb24KCmBgYHtyIGV4cHJlc3Npb25fZGlzdHJpYnV0aW9ufQoKIyBTdGFjayByYXdjb3VudHMgaW50byBzaW5nbGUgdmVjdG9yIApkYXQgPC0gc3RhY2socmF3Y291bnRzKQoKIyBGb3JtYXQgZXhwcmVzc2lvbiBkaXN0cmlidXRpb24gcGxvdCB3aXRoIHRoZSBleHByZXNzaW9uIGxldmVsIGFuZCBkZW5zaXR5IApleHByZXNzaW9uX2Rpc3QgPC0gZ2dwbG90KGRhdCwgYWVzKHggPSBsb2cyKHZhbHVlcysxKSwgIGZpbGw9aW5kLCBsYWJlbCA9IGluZCApKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIAogIHlsYWIoIkRlbnNpdHkiKSArIAogIGdlb21fdGV4dGRlbnNpdHkoaGp1c3QgPSAieW1heCIsIHZqdXN0ID0gMCwKICAgICAgICAgICB0ZXh0X29ubHkgPSBUUlVFLCB0ZXh0X3Ntb290aGluZyA9IDIwKSArIAogICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gdGV4dC5zaXplKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBheGlzLnRleHQuc2l6ZSksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRleHQuc2l6ZSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSBheGlzLnRleHQuc2l6ZSksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yKSwKICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9ibGFuaygpKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDE1KSkKCmV4cHJlc3Npb25fZGlzdAoKI3NhdmUgZmlndXJlCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwgIl9leHByZXNzaW9uX2Rpc3RfIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwgIi52cy4iLCBjb250cm9sLCAiLnBkZiIpKQpleHByZXNzaW9uX2Rpc3QKZGV2Lm9mZigpIAoKYGBgCgojIE5vbi16ZXJvIGdlbmVzIG9ic2VydmVkCgpgYGB7ciBub24temVyb19nZW5lc30KIyBQcmVwYXJlIGRhdGEgYnkgZ2V0dGluZyBsaWJyYXJ5IHNpemVzIGFuZCBub24temVybyBjb3VudHMKeCA8LSBjb2xTdW1zKHJhd2NvdW50cykKeSA8LSBjb2xTdW1zKHJhd2NvdW50cyAhPSAwKSAKZGYgPC0gZGF0YS5mcmFtZSh4LHkpCmRmJGluZCA8LSByb3duYW1lcyhkZikKCiMgQ2FsY3VsYXRlIGF4aXMgbGltaXRzCnhfbWluIDwtIG1pbihkZiR4KQp4X21heCA8LSBtYXgoZGYkeCkKeV9taW4gPC0gbWluKGRmJHkpCnlfbWF4IDwtIG1heChkZiR5KQoKIyBOb24temVybyBwbG90Cm5vbnplcm8gPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSBpbmQsIGxhYmVsID0gaW5kKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoaGp1c3QgPSAtMC4xLCB2anVzdCA9IC0wLjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoeV9taW4sIHlfbWF4KSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKHhfbWluLTFlMywgeF9tYXgrOWU1KSwKICAgIGxhYmVscyA9IHNjYWxlczo6Y29tbWFfZm9ybWF0KHNjYWxlID0gMWUtNiwgIGFjY3VyYWN5ID0gMSkgICMgRm9ybWF0IGxhYmVscyB3aXRob3V0IGRlY2ltYWxzCiAgKSArCiAgeGxhYigiTWlsbGlvbnMgb2YgcmVhZHMiKSArIHlsYWIoIk51bWJlciBvZiBub24temVybyBnZW5lcyBvYnNlcnZlZCIpICsKICBsYWJzKGNvbG9yID0gIlNhbXBsZSIpICsgCiAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSB0ZXh0LnNpemUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gdGV4dC5zaXplKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGF4aXMudGV4dC5zaXplKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjIpLAogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBjb29yZF9jYXJ0ZXNpYW4oKQoKIyBTaG93IG5vbnplcm8gcGxvdApub256ZXJvCgojIFNhdmUgcGxvdAoKY2Fpcm9fcGRmKHBhc3RlMChTeXMuRGF0ZSgpLCAiX25vbi16ZXJvXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsICIudnMuIiwgY29udHJvbCwgIi5wZGYiKSkKbm9uemVybwpkZXYub2ZmKCkgCgpgYGAKCiMgUlBLTSBhbmQgQ1BNIHRyYW5zZm9ybWF0aW9ucwpgYGB7ciBkYXRhX3RyYW5zZm9ybWF0aW9uc30KIyBMb2FkIEdGRiBhbm5vdGF0aW9uIApnZmZfYW5ub3QgPC0gbG9hZF9nZmZfYW5ub3RhdGlvbnMoIi4uLy4uL3Jhdy1kYXRhL3BhZXJ1Z2lub3NhX3BhMTQuZ2ZmIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZF9jb2wgPSAiZ2VuZV9pZCIsIHR5cGUgPSAiZ2VuZSIpCnJvd25hbWVzKGdmZl9hbm5vdCkgPC0gZ2ZmX2Fubm90JGdlbmVfaWQKCmhlYWQoZ2ZmX2Fubm90KQpoZWFkKHJhd2NvdW50cykKZGltKGdmZl9hbm5vdCkKZGltKHJhd2NvdW50cykKCnN1bW1hcnkocm93bmFtZXMoZ2ZmX2Fubm90KSA9PSByb3duYW1lcyhyYXdjb3VudHMpKQpnZmZfYW5ub3QgPC0gZ2ZmX2Fubm90W3Jvd25hbWVzKHJhd2NvdW50cyksXQpzdW1tYXJ5KHJvd25hbWVzKGdmZl9hbm5vdCkgPT0gcm93bmFtZXMocmF3Y291bnRzKSkKCgojIENyZWF0ZSBhbiBleHByZXNzaW9uIG9iamVjdCB3aXRoIGNvdW50cywgbWV0YWRhdGEsIGFuZCBnZW5lIGluZm8KZXhwdCA8LSBjcmVhdGVfZXhwdChjb3VudF9kYXRhZnJhbWUgPSByYXdjb3VudHMsCiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gZ2ZmX2Fubm90KQoKIyBOb3JtYWxpemUgY291bnRzIGxvZzIgQ1BNCmNwbV9ub3JtYWxpemVkX2V4cCA8LSBub3JtYWxpemVfZXhwdChleHB0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInJhdyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19taW4gPSAiMTAiKQoKIyMjIyMjIyBDYWxjdWxhdGUgUlBLTSAjIyMjIyMjIwoKIyBHcmFiIGdlbmUgbGVuZ3RocyBmcm9tIEdGRiAoc2hvdWxkIGJlIGluIGJhc2UgcGFpcnMpCmdlbmVfbGVuZ3RocyA8LSBnZmZfYW5ub3Qkd2lkdGggIApuYW1lcyhnZW5lX2xlbmd0aHMpIDwtIHJvd25hbWVzKGdmZl9hbm5vdCkgICMgc2V0IGdlbmUgbmFtZXMKCiMgTWFrZSBzdXJlIGdlbmVfbGVuZ3RocyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgcmF3Y291bnRzIHJvd3MKZ2VuZV9sZW5ndGhzIDwtIGdlbmVfbGVuZ3Roc1tyb3duYW1lcyhyYXdjb3VudHMpXQoKIyBNYWtlIERHRUxpc3Qgb2JqZWN0IGZvciBlZGdlUgpkZ2UgPC0gREdFTGlzdChjb3VudHMgPSByYXdjb3VudHMpCgojIENhbGN1bGF0ZSBSUEtNIChyZWFkcyBwZXIga2lsb2Jhc2UgcGVyIG1pbGxpb24pCnJwa20gPC0gcnBrbShkZ2UsIGdlbmUubGVuZ3RoID0gZ2VuZV9sZW5ndGhzKQoKIyBXcmFwIFJQS00gaW4gYW4gZXhwZXJpbWVudCBvYmplY3QgdG9vCmV4cHRfcnBrbSA8LSBjcmVhdGVfZXhwdChjb3VudF9kYXRhZnJhbWUgPSBycGttLAogICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm8gPSBnZmZfYW5ub3QpCgojIGxvZzIgdHJhbnNmb3JtIHRoZSBSUEtNIChhZ2Fpbiwgbm8gbm9ybWFsaXphdGlvbiBiZXlvbmQgbG9nKQpycGttX25vcm1hbGl6ZWRfZXhwIDwtIG5vcm1hbGl6ZV9leHB0KGV4cHRfcnBrbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInJhdyIpCgojIEdldCB0aGUgYWN0dWFsIGV4cHJlc3Npb24gbWF0cmljZXMgZnJvbSB0aGUgZXhwZXJpbWVudCBvYmplY3RzCnJwa20gPC0gZXhwcnMocnBrbV9ub3JtYWxpemVkX2V4cCkKY3BtIDwtIGV4cHJzKGNwbV9ub3JtYWxpemVkX2V4cCkKCiMgTWVyZ2UgQ1BNIGFuZCBSUEtNIG1hdHJpY2VzIHdpdGggZ2VuZSBhbm5vdGF0aW9uIGluZm8KY3BtX2Fubm90YXRlZCA8LSBtZXJnZShnZmZfYW5ub3QsIGNwbSwgYnkgPSAwKQpycGttX2Fubm90YXRlZCA8LSBtZXJnZShnZmZfYW5ub3QsIHJwa20sIGJ5ID0gMCkKYGBgCgojIyBIZWF0bWFwIG9mIGFsZ2luYXRlIGdlbmVzClRoaXMgZ2VuZXJhdGVzIGEgc21hbGwgaGVhdG1hcCBvZiB0aGUgYWxnaW5hdGUgZ2VuZXMgYWNyb3NzIHNhbXBsZXMgdG8gdmlzdWFsaXplIGV4cHJlc3Npb24uCgpgYGB7ciBoZWF0bWFwc30KIyBMb29wIHRocm91Z2ggQ1BNIGFuZCBSUEtNIHRvIHBsb3QgYm90aCBoZWF0bWFwcwpmb3IgKHR5cGUgaW4gYygiY3BtIiwgInJwa20iKSkgewogIAogICMgRGVmaW5lIGdlbmUgbGlzdAogIGFsZ19vcGVyb25fZ2VuZXMgPC0gYygKICAgICJhbGdBIiwgImFsZ0YiLCAiYWxnSiIsICJhbGdJIiwgImFsZ0wiLCAiYWxnWCIsICJhbGdHIiwgImFsZ0UiLAogICAgImFsZ0siLCAiYWxnNDQiLCAiYWxnOCIsICJhbGdEIiwgIm11Y0MiLCAibXVjQiIsICJhbGdVIiwgImFsZ1ciLAogICAgImFsZ1AiLCAiYWxnUSIsICJhbGdSIiwgImFsZ1oiLCAiYWxnQyIsICJhbGdCIgogICkKCiAgIyBHZXQgdGhlIHJpZ2h0IGRhdGEgcGVyIHR5cGUgb2YgdHJhbnNmb3JtYXRpb24KICBkYXRhX2Fubm90IDwtIGdldChwYXN0ZTAodHlwZSwgIl9hbm5vdGF0ZWQiKSkKICAKICAjIEZpeCByb3duYW1lcyB1c2luZyBnZW5lIG5hbWUgKG1ha2UgdW5pcXVlKQogIHJvd25hbWVzKGRhdGFfYW5ub3QpIDwtIG1ha2UubmFtZXMoZGF0YV9hbm5vdCRuYW1lLCB1bmlxdWUgPSBUUlVFKQogIAogICMgRHJvcCB1bmRlc2lyZWQgbWV0YWRhdGEgY29sdW1ucwogIGNvbHNfdG9fZXhjbHVkZSA8LSBjKCJSb3cubmFtZXMiLCJzZXFuYW1lcyIsInN0YXJ0IiwiZW5kIiwid2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICJzdHJhbmQiLCJzb3VyY2UiLCJ0eXBlIiwic2NvcmUiLCJwaGFzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgImdlbmVfaWQiLCJOYW1lIiwiRGJ4cmVmIiwiQWxpYXMiLCJuYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAiUGFyZW50IiwibG9jdXMiKQogIGtlZXAgPC0gIW5hbWVzKGRhdGFfYW5ub3QpICVpbiUgY29sc190b19leGNsdWRlCiAgZXhwcl9kYXRhIDwtIGRhdGFfYW5ub3RbLCBrZWVwXQogIAogICMgRXh0cmFjdCBtYXRyaXggZm9yIGFsZyBnZW5lcwogIGFsZ19nZW5lcyA8LSBleHByX2RhdGFbYWxnX29wZXJvbl9nZW5lcywgLCBkcm9wID0gRkFMU0VdCiAgbWF0IDwtIGFsZ19nZW5lcyAtIHJvd01lYW5zKGFsZ19nZW5lcykKICAKICAjIFB1bGwgc2FtcGxlIGFubm90YXRpb25zCiAgYW5ubyA8LSBhcy5kYXRhLmZyYW1lKG1ldGFkYXRhWywgYygiY29uZGl0aW9uIiwgImluZHVjZWQiKV0pCiAgY29sbmFtZXMoYW5ubykgPC0gYygiQ29uZGl0aW9uIiwgIkluZHVjZWQiKQogIAogICMgQ29sb3Igc2V0dGluZ3MgZm9yIGFubm90YXRpb24KICMgYW5uX2NvbG9ycyA8LSBsaXN0KAogIyAgQ29uZGl0aW9uID0gYygiTEItRE1TTyIgPSAiI0Q5NUYwMiIsICJMQi1JUFRHIiA9ICIjNjZBNjFFIiksCiAjICBJbmR1Y2VkID0gYygibm8iID0gImxpZ2h0Z3JleSIsICJ5ZXMiID0gImdyYXkyNyIpCiAjICkKICAKICAjIFNjYWxlIGRhdGEgYnkgcm93IChaLXNjb3JlIHBlciBnZW5lKQogIHNjYWxlZF9tYXQgPC0gdChzY2FsZSh0KG1hdCkpKQoKICAjIEJ1aWxkIGhlYXRtYXAKICBodCA8LSBIZWF0bWFwKAogICAgc2NhbGVkX21hdCwKICAgIG5hbWUgPSAiWi1zY29yZSIsCiAgICB0b3BfYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gYW5ubyMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY29sID0gYW5uX2NvbG9ycwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsCiAgICByb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwKICAgIGNvbHVtbl9uYW1lc19zaWRlID0gImJvdHRvbSIsCiAgICBjb2x1bW5fbmFtZXNfcm90ID0gNDUsCiAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSwKICAgIHNob3dfcm93X2RlbmQgPSBUUlVFLAogICAgc2hvd19jb2x1bW5fZGVuZCA9IFRSVUUKICApCiAgCiAgIyBEcmF3IGFuZCBzYXZlCiAgZHJhdyhodCkKICAKICBjYWlyb19wZGYocGFzdGUwKFN5cy5EYXRlKCksICJfYWxnX2hlYXRtYXBfIiwgdHlwZSwgIl8iLCBleHAsICJfIiwgdHJlYXRtZW50LCAiLnZzLiIsIGNvbnRyb2wsICIucGRmIikpCiAgZHJhdyhodCkKICBkZXYub2ZmKCkKfQoKYGBgCgojIERFU2VxCmBgYHtyIERFU2VxfQojIENyZWF0ZSBERVNlcURhdGFTZXQKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoCiAgY291bnREYXRhID0gcmF3Y291bnRzLAogIGNvbERhdGEgPSBtZXRhZGF0YSwKICBkZXNpZ24gPSBkZXNpZ25fZm9ybXVsYQopCgojIENoZWNrIG51bWJlciBvZiBnZW5lcyBiZWZvcmUgZmlsdGVyaW5nCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgYmVmb3JlIGZpbHRlcmluZzoiKQpucm93KGRkcykKCiMgRmlsdGVyOiBrZWVwIGdlbmVzIHdpdGggY291bnRzID49MTAgaW4gYXQgbGVhc3QgMiBzYW1wbGVzCnByaW50KCJGaWx0ZXJpbmcgZ2VuZXMgd2l0aCBjb3VudHMgPj0xMCBpbiBhdCBsZWFzdCAyIHNhbXBsZXMiKQprZWVwIDwtIHJvd1N1bXMoY291bnRzKGRkcykgPj0gMTApID49IDIgCmRkc19maWx0ZXJlZCA8LSBkZHNba2VlcCwgXQoKIyBDaGVjayBudW1iZXIgb2YgZ2VuZXMgYWZ0ZXIgZmlsdGVyaW5nCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgYWZ0ZXIgZmlsdGVyaW5nOiIpCm5yb3coZGRzX2ZpbHRlcmVkKQoKIyBSdW4gREVTZXEgb24gdGhlIGZpbHRlcmVkIGRhdGFzZXQKZGRzX2ZpbmFsIDwtIERFU2VxKGRkc19maWx0ZXJlZCkKCiMgU2hvdyBhdmFpbGFibGUgcmVzdWx0cwpyZXN1bHRzTmFtZXMoZGRzX2ZpbmFsKQoKIyBQbG90IGRpc3BlcnNpb24gZXN0aW1hdGVzCnBsb3REaXNwRXN0cyhkZHNfZmluYWwpCmBgYAoKIyBTYXZlIERFIHRhYmxlcyAKYGBge3Igc2F2ZV90YWJsZXN9CnJlcyA8LSByZXN1bHRzKGRkc19maW5hbCwgY29udHJhc3QgPSBjKCJleHBfMSIsICJ0cmVhdG1lbnQiLCAiY29udHJvbCIpKQpyZXNkZiA8LSBhcy5kYXRhLmZyYW1lKHJlcykKcmVzZGYkZ2VuZV9pZCA8LSByb3duYW1lcyhyZXNkZikKCmNwbSA8LSBhcy5kYXRhLmZyYW1lKGNwbSkKcnBrbSA8LSBhcy5kYXRhLmZyYW1lKHJwa20pCgojIGFwcGVuZCB0eXBlIG9mIHZhbHVlIHRvIHRoZSBkYXRhZnJhbWUgICAKY29sbmFtZXMocnBrbSkgPC0gcGFzdGUwKGNvbG5hbWVzKHJwa20pLCAiX3Jwa20iKQpjb2xuYW1lcyhjcG0pIDwtIHBhc3RlMChjb2xuYW1lcyhjcG0pLCAiX2NwbSIpCnJhd2NvdW50czIgPC0gcmF3Y291bnRzCmNvbG5hbWVzKHJhd2NvdW50czIpIDwtIHBhc3RlMChjb2xuYW1lcyhyYXdjb3VudHMyKSwgIl9yYXdjb3VudHMiKQoKIyBlbnN1cmUgY29sdW1uIGdlbmVfaWQgaXMgdGhlcmUKcnBrbSRnZW5lX2lkIDwtIHJvd25hbWVzKHJwa20pCmNwbSRnZW5lX2lkIDwtIHJvd25hbWVzKGNwbSkKcmF3Y291bnRzMiRnZW5lX2lkIDwtIHJvd25hbWVzKHJhd2NvdW50czIpCgpnZmZfYW5ub3QgPC0gZ2ZmX2Fubm90W3Jvd25hbWVzKHJlc2RmKSxdCgpkaW0ocmVzZGYpCiMgbWVyZ2Ugd2l0aCBzaWdnZW5lcwpyZXNkZiA8LSBmdWxsX2pvaW4ocmVzZGYsIGdmZl9hbm5vdCwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKaGVhZChyZXNkZikKCnBhX2dvIDwtIHJlYWQuY3N2KCIuLi8uLi9yYXctZGF0YS8yMDg5NjNfbWljcm9iZXMub25saW5lLmNzdiIsIGhlYWRlciA9IFRSVUUpCmhlYWQocGFfZ28pCgpjb2xfdG9fcmVtb3ZlIDwtIGludGVyc2VjdChjb2xuYW1lcyhwYV9nbyksY29sbmFtZXMocmVzZGYpKQpjb2xfdG9fcmVtb3ZlIDwtIHNldGRpZmYoY29sX3RvX3JlbW92ZSwgIkFsaWFzIikgIyByZXR1cm5zIGFsbCBleGNlcHQgdGhlIHNlY29uZCB2ZWN0b3IKCnBhX2dvIDwtIHBhX2dvICU+JSBzZWxlY3QoLWFsbF9vZihjb2xfdG9fcmVtb3ZlKSkKCnJlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcnBrbSwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKcmVzZGYgPC0gZnVsbF9qb2luKHJlc2RmLCBjcG0sIGJ5ID0gImdlbmVfaWQiLCBjb3B5ID0gRkFMU0UpCnJlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcmF3Y291bnRzMiwgYnkgPSAiZ2VuZV9pZCIsIGNvcHkgPSBGQUxTRSkKI3Jlc2RmIDwtIGZ1bGxfam9pbihyZXNkZiwgcGFfZ28sIGJ5ID0gIkFsaWFzIiwgY29weSA9IEZBTFNFKQpyZXNkZiA8LSBtZXJnZShyZXNkZiwgcGFfZ28sIGJ5ID0gIkFsaWFzIiwgY29weSA9IEZBTFNFKQoKaGVhZChyZXNkZikKd3JpdGUuY3N2KHJlc2RmLCBwYXN0ZTAoU3lzLkRhdGUoKSAsICJfcmVzdWx0c18iLGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgU2F2ZSBERUcgbGlzdApgYGB7ciBzYXZlX2RlZ30KIyBmaWx0ZXIgZm9yIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIChMRkMgPj0gMywgcGFkaiA8IHB2YWxfY3V0b2ZmKQpkaW0ocmVzZGYpCmhlYWQocmVzZGYpCgpzdW1tYXJ5KGlzLm5hKHJlc2RmJGxvZzJGb2xkQ2hhbmdlKSkKc3VtbWFyeShpcy5uYShyZXNkZiRwYWRqKSkKCnNpZ19nZW5lcyA8LSByZXNkZlthYnMocmVzZGYkbG9nMkZvbGRDaGFuZ2UpID49IGxvZ2ZjX2N1dG9mZiAmIHJlc2RmJHBhZGogPCBwdmFsX2N1dG9mZiwgXSAgJT4lIGRyb3BfbmEobG9nMkZvbGRDaGFuZ2UpCnNpZ19nZW5lcyRkaXJlY3Rpb24gPC0gaWZlbHNlKHNpZ19nZW5lcyRsb2cyRm9sZENoYW5nZSA+IDAsICJ1cCIsICJkb3duIikKCnN1bW1hcnkoaXMubmEoc2lnX2dlbmVzJGxvZzJGb2xkQ2hhbmdlKSkKc3VtbWFyeShpcy5uYShzaWdfZ2VuZXMkcGFkaikpCgpkaW0oc2lnX2dlbmVzKQpoZWFkKHNpZ19nZW5lcykKd3JpdGUuY3N2KHNpZ19nZW5lcywgcGFzdGUwKFN5cy5EYXRlKCksIl9zaWduaWZpY2FudGdlbmVzXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMgUENBIHBsb3QgCmBgYHtyIFBDQX0KdnN0IDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gcmF3Y291bnRzLCBjb2xEYXRhID0gbWV0YWRhdGEsIGRlc2lnbiA9IH4gZXhwXzEgKyBiYXRjaCkKCiMgVmFyaWFuY2Ugc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb25zCnZzZCA8LSB2c3QodnN0LCBibGluZCA9IFRSVUUpCgojIFBDQSBwbG90CnBjYURhdGEgPC0gcGxvdFBDQSh2c2QsIGludGdyb3VwID0gYygiZXhwXzEiLCAiYmF0Y2giLCAiY29uZGl0aW9uIiksIHJldHVybkRhdGEgPSBUUlVFKQpwZXJjZW50VmFyIDwtIHJvdW5kKDEwMCAqIGF0dHIocGNhRGF0YSwgInBlcmNlbnRWYXIiKSkKCiMgQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIGFic29sdXRlIHZhbHVlIGFtb25nIFBDMSBhbmQgUEMyCm1heF9hYnNfdmFsIDwtIG1heChjKGFicyhtaW4ocGNhRGF0YSRQQzEpKSwgYWJzKG1pbihwY2FEYXRhJFBDMikpLCBhYnMobWF4KHBjYURhdGEkUEMxKSksIGFicyhtYXgocGNhRGF0YSRQQzIpKSkpCgpheGlzX3NpemUgPC0gMTAKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiQXJpYWwiKSkKCnBjYSA8LSBnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBjb2xvciA9IGNvbmRpdGlvbiwgc2hhcGUgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyWzJdLCAiJSB2YXJpYW5jZSIpKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2KSkgKwogIGNvb3JkX2ZpeGVkKHJhdGlvID0gMSwgeGxpbSA9IGMoLW1heF9hYnNfdmFsLCBtYXhfYWJzX3ZhbCksIHlsaW0gPSBjKC1tYXhfYWJzX3ZhbCwgbWF4X2Fic192YWwpKSArCiAgbGFicyhjb2xvciA9ICJjb25kaXRpb24iLCBzaGFwZSA9ICJjb25kaXRpb24iKSArCiAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkNvbmRpdGlvbiIpLCAgIyBBZGp1c3Qgc2l6ZSBvZiBzaGFwZSBsZWdlbmQKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkNvbmRpdGlvbiIpKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gYXhpc19zaXplKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMC4yKSwKICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUobGluZXdpZHRoID0gMCwgY29sb3IgPSAiYmxhY2siKSwgICMgU2V0IHRoZSBheGlzIGxpbmUgbGluZXdpZHRoCiAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSksICAjIFNldCB0aGUgcGFuZWwgYm9yZGVyIGxpbmV3aWR0aAogIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpICAjIFNldCBsZWdlbmQga2V5IGJhY2tncm91bmQgdG8gd2hpdGUgYW5kIHJlbW92ZSBib3JkZXIKICApCgpwcmludChwY2EpCgpjYWlyb19wZGYocGFzdGUwKFN5cy5EYXRlKCksIl9wY2FfIixleHAsICJfIiwgdHJlYXRtZW50LCIudnMuIiwgY29udHJvbCwiLnBkZiIsIHNlcCA9ICIiKSkKcGNhCmRldi5vZmYoKQoKYGBgCgojIFZvbGNhbm8gcGxvdApgYGB7ciB2b2xjYW5vfQpzZXF1ZW5jZSA8LSBjKCJ0cmVhdG1lbnQiKQoKZm9yIChpIGluIHNlcXVlbmNlKSB7CiAgICBzZXQuc2VlZCgwKQogICAgcmVzIDwtIHJlc3VsdHMoZGRzX2ZpbmFsLCBjb250cmFzdCA9IGMoImV4cF8xIiwgaSwgImNvbnRyb2wiKSkKCiAgZ3AyIDwtIHdlc19wYWxldHRlcyRaaXNzb3UxCiAga2V5IDwtIHJlYWQuY3N2KCIuLi8uLi9yYXctZGF0YS9wYTE0X2dlbmVfa2V5LmNzdiIsICBoZWFkZXIgPSBUUlVFKQoKICByb3duYW1lcyhrZXkpIDwtIGtleSRnZW5lX2lkCgogIHJlcyA8LSBtZXJnZShrZXksIGFzLmRhdGEuZnJhbWUocmVzKSwgYnk9MCkKICByZXMgPC0gYXMuZGF0YS5mcmFtZShyZXMpCiAgcmVzJEFsaWFzIDwtIHJvd25hbWVzKHJlcykKCiAjIERlZmluZSBnZW5lIGxpc3QKICBhbGdfZ2VuZXMgPC0gYygKICAgICJhbGdBIiwgImFsZ0YiLCAiYWxnSiIsICJhbGdJIiwgImFsZ0wiLCAiYWxnWCIsICJhbGdHIiwgImFsZ0UiLAogICAgImFsZ0siLCAiYWxnNDQiLCAiYWxnOCIsICJhbGdEIiwgIm11Y0MiLCAibXVjQiIsICJhbGdVIiwgImFsZ1ciLAogICAgImFsZ1AiLCAiYWxnUSIsICJhbGdSIiwgImFsZ1oiLCAiYWxnQyIsICJhbGdCIgogICkKCmxvZ2ZjX2N1dG9mZgprZXl2YWxzIDwtIGlmZWxzZSgKIHJlcyRsb2cyRm9sZENoYW5nZSA8PSAtbG9nZmNfY3V0b2ZmICYgcmVzJHBhZGogPD0gcHZhbF9jdXRvZmYsIGdwMlsxXSwKICBpZmVsc2UocmVzJGxvZzJGb2xkQ2hhbmdlID49IGxvZ2ZjX2N1dG9mZiAmIHJlcyRwYWRqIDw9IHB2YWxfY3V0b2ZmLCBncDJbNV0sCiAgICAgICAgICdsaWdodGdyZXknKSkKa2V5dmFsc1tpcy5uYShrZXl2YWxzKV0gPC0gJ2xpZ2h0Z3JleScKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSBncDJbNV1dIDwtICdVcC1yZWd1bGF0ZWQnCm5hbWVzKGtleXZhbHMpW2tleXZhbHMgPT0gJ2xpZ2h0Z3JleSddIDwtICdOUycKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSBncDJbMV1dIDwtICdEb3duLXJlZ3VsYXRlZCcKCnZvbGNhbm8gPC0gRW5oYW5jZWRWb2xjYW5vKHJlcywKICAgICAgICAgICAgICAgICAgICAgbGFiID0gcmVzW1sibmFtZSJdXSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gYWxnX2dlbmVzLAogICAgICAgICAgICAgICAgICAgICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywKICAgICAgICAgICAgICAgICAgICAgeSA9ICdwYWRqJywKICAgICAgICAgICAgICAgICAgICAgeGxhYiA9IGJxdW90ZSh+TG9nWzJdfiAnZm9sZCBjaGFuZ2UnKSwKICAgICAgICAgICAgICAgICAgICAgcEN1dG9mZiA9IHB2YWxfY3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IGxvZ2ZjX2N1dG9mZiwKICAgICAgICAgICAgICAgICAgICAgY3V0b2ZmTGluZVR5cGUgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMSwKICAgICAgICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDMuMCwKICAgICAgICAgICAgICAgICAgICAgYXhpc0xhYlNpemUgPSAxNCwKICAgICAgICAgICAgICAgICAgICAgbGFiQ29sID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgICAgICAgbGFiRmFjZSA9ICdib2xkJywKICAgICAgICAgICAgICAgICAgICAgI2NvbCA9IGMoJ2dyZXknLCBncDJbMl0sIGdwMlszXSwgZ3AyWzFdKSwKICAgICAgICAgICAgICAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscywKICAgICAgICAgICAgICAgICAgICAgY29sQWxwaGEgPSA1LzUsCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZExhYlNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgICAgICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgYXJyb3doZWFkcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgIGdyaWRsaW5lcy5tYWpvciA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICBib3JkZXJXaWR0aCA9IDAuMywKICAgICAgICAgICAgICAgICAgICAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKHRyZWF0bWVudCwiIHZzICIsIGNvbnRyb2wsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgI2NhcHRpb24gPSBwYXN0ZTAoInRvdGFsID0gIiwgbnJvdyh0b3B0YWJsZSksICIgdmFyaWFibGVzIiksCiAgICAgICAgICAgICAgICAgICAgIGNhcHRpb24gPSBwYXN0ZTAoIlZvbGNhbm8gcGxvdCB3aXRoIGxvZzIgRkMgb2YgIiwgbG9nZmNfY3V0b2ZmLCIgYW5kIFAgdmFsdWUgb2YgIixwdmFsX2N1dG9mZiwgIi4iKSwKICAgICAgICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICN5bGltID0gYygwLDEwKSwKICAgICAgICAgICAgICAgICAgICAgY29sQ29ubmVjdG9ycyA9ICdibGFjaycpICsgCiAgICAgIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9MC4yKSkgIyArCiAjIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKC01LCAtMi41LCAwLCAyLjUsIDUpLCBsaW1pdHMgPSBjKC02LDYpKQoKcHJpbnQodm9sY2FubykKCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwiX3ZvbGNhbm9fIiwgZXhwLCAiXyIsIHRyZWF0bWVudCwiLnZzLiIsIGNvbnRyb2wsIi5wZGYiLCBzZXAgPSAiIikpCnByaW50KHZvbGNhbm8pCmRldi5vZmYoKQp9CgpgYGAKCiMgTUEgcGxvdApgYGB7ciBNQV9wbG90fQpzZXF1ZW5jZSA8LSBjKCJ0cmVhdG1lbnQiKQoKZm9yIChpIGluIHNlcXVlbmNlKSB7CiAgICBzZXQuc2VlZCgwKQoKcmVzIDwtIHJlc3VsdHMoZGRzX2ZpbmFsLCBjb250cmFzdCA9IGMoImV4cF8xIiwgaSwgImNvbnRyb2wiKSkKCmdwMiA8LSB3ZXNfcGFsZXR0ZXMkWmlzc291MQoKcmVzJGdlbmVfaWQgPC0gcm93bmFtZXMocmVzKQpyZXMgPC0gYXMuZGF0YS5mcmFtZShyZXMpCmhlYWQocmVzKQpyZXMgPC0gZnVsbF9qb2luKGtleSwgYXMuZGF0YS5mcmFtZShyZXMpLCBieT0iZ2VuZV9pZCIpCnJvd25hbWVzKHJlcykgPC0gcmVzJEFsaWFzCgphbnkoaXMubmEocmVzKSkgICMgQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBOQXMKCnJlcyA8LSByZXMgJT4lIGZpbHRlcighaXMubmEoYmFzZU1lYW4pKQoKCm1hIDwtIGdnbWFwbG90KHJlcywgCiAgICAgICAgICAgICAgIGZkciA9IHB2YWxfY3V0b2ZmLCAKICAgICAgICAgICAgICAgZmMgPSAyXihsb2dmY19jdXRvZmYpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IDEsCiAgICAgICAgICAgICAgIHBhbGV0dGUgPSBjKChncDJbNV0pLCAoZ3AyWzFdKSksCiAgICAgICAgICAgICAgIHNlbGVjdC50b3AubWV0aG9kID0gImZjIiwKICAgICAgICAgICAgICMgIHlsaW0gPSBjKC0xNSwxNSksCiAgICAgICAgICAgICAgIGxlZ2VuZCA9ICJib3R0b20iLCAKICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZTAodHJlYXRtZW50LCIgdnMgIiwgY29udHJvbCwgc2VwID0gIiIpLAogICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJWb2xjYW5vIHBsb3Qgd2l0aCBsb2cyIEZDIG9mICIsIGxvZ2ZjX2N1dG9mZiwiIGFuZCBQIHZhbHVlIG9mICIscHZhbF9jdXRvZmYsICIuIiksCiAgICAgICAgICAgICAgIGZvbnQubGFiZWwgPSBjKCAxMiksIAogICAgICAgICAgICAgbGFiZWwucmVjdGFuZ2xlID0gRkFMU0UsCiAgICAgICAgICAgICAgZ2VuZW5hbWVzID0gcmVzJG5hbWUsCiAgICAgICAgICAgICAgZm9udC5sZWdlbmQgPSBjKDEyKSwKICAgICAgICAgICAgICAgZm9udC5tYWluID0gYygiYm9sZCIsIDE0KSwKICAgICAgICAgICAgICAgYWxwaGEgPSAxLjUsCiAgICAgICAgICAgICAgIGdndGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkID1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSkpIApwcmludChtYSkKCmNhaXJvX3BkZihwYXN0ZTAoU3lzLkRhdGUoKSwiX21hXyIsIGV4cCwgIl8iLCB0cmVhdG1lbnQsIi52cy4iLCBjb250cm9sLCIucGRmIikpCnByaW50KG1hKQpkZXYub2ZmKCkKfQpgYGAKCg==