1 Important note

I copied my index_rofA and just performed replace-string on it for the times and strains:

  1. s/revert/complement/g
  2. s/transition/start/g
  3. s/exponential/e20m/g
  4. s/stationary/e60m/g

2 S.pyogenes 5448 pdxR RNASeq version: 202204

2.1 Preprocessing

I used my cyoa tool to process these samples by doing the following:

  1. Copying the data from the sequencer into the directory ‘preprocessing/’
  2. Used a slightly involved shell command to create a directory for each sample and copy the reads for it to the ‘unprocessed/’ subdirectory within it.
  3. invoked the following:
cd preprocessing
start=$(pwd)
for i in $(/bin/ls -d ./*)
do
  cd $i
  rm -rf outputs scripts
  cyoa --task pipe --method prnas --species spyogenes_5005 \
       --gff_type gene --gff_tag locus_tag \
       --input $(/bin/ls unprocessed/* | tr '\n' ':' | sed 's/:$//g')
  cd $start
done

The above for loop goes into each sample and does the following:

  1. Trims the data, heavily compresses the outputs.
  2. Runs fastqc
  3. Runs hisat2 using my spyogenes_5005 indices.
  4. Converts the sam alignment to sorted/indexed bam.
  5. Makes a couple of extra copies of it with some filters.
  6. Compresses the aligned/unaligned reads.
  7. Runs htseq-count on the alignments to count reads/gene.

Note the following steps were not actually run because I had a speeling error. But since they are not necessary for the explicitly RNASeq analyses I first want to do, I ignored it. I am curious though to see if there are other mutations in these strains, so I will likely run those portions manually.

  1. Runs freebayes on the alignments to look for variants.
  2. Sorts/compresses the freebayes output.
  3. Does some parsing of the freebayes output and provides some tables about where mutations were observed.

2.2 Collect annotation information

Same two primary annotation sources, the gff file used for mapping/counting, and microbesonline.org. Note that since I moved to just downloading the material from the web interface, I no longer have a handy method to get the taxon ID, so I go there and hunt down the taxId manually.

gff_annot <- load_gff_annotations("reference/spyogenes_5005.gff", type = "CDS")
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = TRUE)
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = FALSE)
## Had a successful gff import with rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = FALSE)
## Returning a df with 19 columns and 1841 rows.
rownames(gff_annot) <- gff_annot[["locus_tag"]]
head(gff_annot)
##               seqnames start  end width strand                 source type
## M5005_Spy0001 CP000017   232 1587  1356      + EMBL/GenBank/SwissProt  CDS
## M5005_Spy0002 CP000017  1742 2878  1137      + EMBL/GenBank/SwissProt  CDS
## M5005_Spy0003 CP000017  2953 3150   198      + EMBL/GenBank/SwissProt  CDS
## M5005_Spy0004 CP000017  3480 4595  1116      + EMBL/GenBank/SwissProt  CDS
## M5005_Spy0005 CP000017  4665 5234   570      + EMBL/GenBank/SwissProt  CDS
## M5005_Spy0006 CP000017  5237 8740  3504      + EMBL/GenBank/SwissProt  CDS
##               score phase codon_start gene     locus_tag  old_locus_tag
## M5005_Spy0001    NA     1           1 dnaA M5005_Spy0001 M5005_Spy_0001
## M5005_Spy0002    NA     1           1 dnaN M5005_Spy0002 M5005_Spy_0002
## M5005_Spy0003    NA     1           1 <NA> M5005_Spy0003 M5005_Spy_0003
## M5005_Spy0004    NA     1           1 <NA> M5005_Spy0004 M5005_Spy_0004
## M5005_Spy0005    NA     1           1  pth M5005_Spy0005 M5005_Spy_0005
## M5005_Spy0006    NA     1           1 trcF M5005_Spy0006 M5005_Spy_0006
##                                                 product protein_id transl_table
## M5005_Spy0001 chromosomal replication initiator protein AAZ50620.1           11
## M5005_Spy0002             DNA polymerase III beta chain AAZ50621.1           11
## M5005_Spy0003                putative cytosolic protein AAZ50622.1           11
## M5005_Spy0004                       GTP-binding protein AAZ50623.1           11
## M5005_Spy0005                   peptidyl-tRNA hydrolase AAZ50624.1           11
## M5005_Spy0006      transcription-repair coupling factor AAZ50625.1           11
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   translation
## M5005_Spy0001                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             MTENEQIFWNRVLELAQSQLKQATYEFFVHDARLLKVDKHIATIYLDQMKELFWEKNLKDVILTAGFEVYNAQISVDYVFEEDLMIEQNQTKINQKPKQQALNSLPTVTSDLNSKYSFENFIQGDENRWAVAASIAVANTPGTTYNPLFIWGGPGLGKTHLLNAIGNSVLLENPNARIKYITAENFINEFVIHIRLDTMDELKEKFRNLDLLLIDDIQSLAKKTLSGTQEEFFNTFNALHNNNKQIVLTSDRTPDHLNDLEDRLVTRFKWGLTVNITPPDFETRVAILTNKIQEYNFIFPQDTIEYLAGQFDSNVRDLEGALKDISLVANFKQIDTITVDIAAEAIRARKQDGPKMTVIPIEEIQAQVGKFYGVTVKEIKATKRTQNIVLARQVAMFLAREMTDNSLPKIGKEFGGRDHSTVLHAYNKIKNMISQDESLRIEIETIKNKIK
## M5005_Spy0002                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      MIQFSINRTLFIHALNTTKRAISTKNAIPILSSIKIEVTSTGVTLTGSNGQISIENTIPVSNENAGLLITSPGAILLEASFFINIISSLPDISINVKEIEQHQVVLTSGKSEITLKGKDVDQYPRLQEVSTENPLILKTKLLKSIIAETAFAASLQESRPILTGVHIVLSNHKDFKAVATDSHRMSQRLITLDNTSADFDVVIPSKSLREFSAVFTDDIETVEVFFSPSQILFRSEHISFYTRLLEGNYPDTDRLLMTEFETEVVFNTQSLRHAMERAFLISNATQNGTVKLEITQNHISAHVNSPEVGKVNEDLDIVSQSGSDLTISFNPTYLIESLKAIKSETVKIHFLSPVRPFTLTPGDEEESFIQLITPVRTN
## M5005_Spy0003                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               MYQIGSFVEMKKPHACVIKETGKKANQWKVLRVGADIKIQCTNCQHVIMMSRYDFERKLKKVLQP
## M5005_Spy0004                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             MALTAGIVGLPNVGKSTLFNAITKAGAEAANYPFATIDPNVGMVEVPDERLQKLTELITPKKTVPTTFEFTDIAGIVKGASRGEGLGNKFLANIREIDAIVHVVRAFDDENVMREQGREDAFVDPIADIDTINLELILADLESINKRYARVEKMARTQKDKESVAEFNVLQKIKPVLEDGKSARTIEFTEDEAKVVKGLFLLTTKPVLYVANVDEDKVANPDGIDYVKQIRDFAATENAEVVVISARAEEEISELDDEDKEEFLEAIGLTESGVDKLTRAAYHLLGLGTYFTAGEKEVRAWTFKRGIKAPQAAGIIHSDFERGFIRAVTMSYDDLMTYGSEKAVKEAGRLREEGKEYVVQDGDIMEFRFNV
## M5005_Spy0005                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   MVKMIVGLGNPGSKYEKTKHNIGFMAIDNIVKNLDVTFTDDKNFKAQIGSTFINHEKVYFVKPTTFMNNSGIAVKALLTYYNIDITDLIVIYDDLDMEVSKLRLRSKGSAGGHNGIKSIIAHIGTQEFNRIKVGIGRPLKGMTVINHVMGQFNTEDNIAISLTLDRVVNAVKFYLQENDFEKTMQKFNG
## M5005_Spy0006 MDILELFSQNKKVQSWHSGLTTLGRQLVMGLSGSSKTLAIASAYLDDQKKIVVVTSTQNEVEKLASDLSSLLDEELVFQFFADDVAAAEFIFASMDKALSRIETLQFLRNPKSQGVLIVSLSGLRILLPNPDVFTKSQIQLTVGEDYDSDTLTKQLMTIGYQKVSQVISPGEFSRRGDILDIYEITQELPYRLEFFGDDIDSIRQFHPETQKSFEQLEGIFINPASDLIFEVSDFQRGIEQLEKALQTAQDDKKSYLEDVLAVSKNGFKHKDIRKFQSLFYEKEWSLLDYIPKGTPIFFDDFQKLVDKNARFDLEIANLLTEDLQQGKALSNLNYFTDNYRELRHYKPATFFSNFHKGLGNIKFDQMHQLTQYAMQEFFNQFPLLIDEIKRYQKNQTTVIVQVESQYAYERLEKSFQDYQFRLPLVSANQIVSRESQIVIGAISSGFYFADEKLALITEHEIYHKKIKRRARRSNISNAERLKDYNELAVGDYVVHNVHGIGRFLGIETIQIQGIHRDYVTIQYQNSDRISLPIDQISSLSKYVSADGKEPKINKLNDGRFQKTKQKVARQVEDIADDLLKLYAERSQQKGFSFSPDDDLQRAFDDDFAFVETEDQLRSIKEIKADMESMQPMDRLLVGDVGFGKTEVAMRAAFKAVNDHKQVAVLVPTTVLAQQHYENFKARFENYPVEVDVLSRFRSKKEQAETLERVRKGQIDIIIGTHRLLSKDVVFSDLGLIVIDEEQRFGVKHKETLKELKTKVDVLTLTATPIPRTLHMSMLGIRDLSVIETPPTNRYPVQTYVLENNPGLVREAIIREMDRGGQIFYVYNKVDTIEKKVAELQELVPEASIGFVHGQMSEIQLENTLIDFINGDYDVLVATTIIETGVDISNVNTLFIENADHMGLSTLYQLRGRVGRSNRIAYAYLMYRPDKVLTEVSEKRLEAIKGFTELGSGFKIAMRDLSIRGAGNILGASQSGFIDSVGFEMYSQLLEQAIASKQGKTTVRQKGNTEINLQIDAYLPDDYIADERQKIDIYKRIREIQSREDYLNLQDELMDRFGEYPDQVAYLLEIALLKHYMDNAFAELVERKNNQVIVRFEVTSLTYFLTQDYFEALSKTHLKAKISEHQGKIDIVFDVRHQKDYRILEELMLFGERLSEIKIRKNNSVFK
##               eC_number note
## M5005_Spy0001           <NA>
## M5005_Spy0002   2.7.7.7 <NA>
## M5005_Spy0003           <NA>
## M5005_Spy0004           <NA>
## M5005_Spy0005  3.1.1.29 <NA>
## M5005_Spy0006           <NA>
microbes_annot <- load_microbesonline_annotations(species="5005")
## Found 1 entry.
## Streptococcus pyogenes MGAS5005Firmicutesyes2005-08-25yes101950293653
## The species being downloaded is: Streptococcus pyogenes MGAS5005
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=293653;export=tab
microbes_annot <- as.data.frame(microbes_annot)
rownames(microbes_annot) <- make.names(gsub(x=microbes_annot[["sysName"]],
                                            pattern="Spy_", replacement="Spy"), unique=TRUE)

both_annot <- merge(gff_annot, microbes_annot, by="row.names", all.y=TRUE)
rownames(both_annot) <- both_annot[["Row.names"]]
both_annot[["Row.names"]] <- NULL

2.3 Rerunning my fasta36 mapper across strains

Once upon a time I wrote a little tool to compare closely species/strains. It is essentially a poor-man’s ortholog search. It has been a very long time since last I used it, and it required some modifications in order to work properly. The most notable problem is that the pathnames it uses are too long for fasta36. I shortened them and fixed a couple of old errors and it appears to work again.

single_hits <- readr::read_tsv("single_multi/outputs/fasta_spyogenes_5448_cds_spyogenes_5005_cds/spyogenes_5448_cds_singles.txt")
## Rows: 1340 Columns: 2
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (2): AKK69518.1, AAZ50620.1:1.000:0
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
colnames(single_hits) <- c("from", "to")
single_hits[["to"]] <- gsub(pattern="(^.*?):.*$", replacement="\\1",
                            x=single_hits[["to"]], perl=TRUE)
## The gff annotation has the protein_id column matching this cds entry.

single_both <- merge(mgas_annot, single_hits, by.x="protein_id", by.y="from", all.x=TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'mgas_annot' not found
single_both <- merge(single_both, ref_gff_annot, by.x="to", by.y="protein_id", all.x=TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'single_both' not found
## Now pick up the missing old_locus_tags and put in the 5448 IDs
missing_ids <- is.na(single_both[["old_locus_tag"]])
## Error in eval(expr, envir, enclos): object 'single_both' not found
new_ids <- single_both[missing_ids, "locus_tag.x"]
## Error in eval(expr, envir, enclos): object 'single_both' not found
single_both[missing_ids, "old_locus_tag"] <- new_ids
## Error in eval(expr, envir, enclos): object 'new_ids' not found
single_both <- merge(single_both, microbes_annot, by.x="old_locus_tag", by.y="sysName", all.x=TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'single_both' not found
rownames(single_both) <- make.names(single_both[["gene_id"]], unique=TRUE)
## Error in make.names(single_both[["gene_id"]], unique = TRUE): object 'single_both' not found

2.4 Create expressionSet

Note that I did the following to the sample sheet provided by Dr. McIver:

  1. Changed the dP_R20_4 sample to dP_R20_2 (The original sample name is still there are the original column).
  2. Added columns at the end containing the count table locations.
  3. Added columns ‘short_media’, ‘growth_phase’, ‘genotype’ which hopefully contain the relevant metadata extracted from the sample descriptions.
  4. Added a column ‘Experiment’ which is either ‘rofA’ or ‘pdxR’.
pdxr_expt <- create_expt(metadata = "sample_sheets/all_samples.xlsx",
                        gene_info = both_annot, file_column = "spyogenes5005genecounts") %>%
  subset_expt(subset="experiment=='pdxR'") %>%
  set_expt_conditions(fact="genotype") %>%
  set_expt_batches(fact="growthphase")
## Reading the sample metadata.
## Did not find the condition column in the sample sheet.
## Filling it in as undefined.
## Did not find the batch column in the sample sheet.
## Filling it in as undefined.
## The sample definitions comprises: 72 rows(samples) and 27 columns(metadata fields).
## Matched 1926 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 1926 features and 72 samples.
## subset_expt(): There were 72, now there are 36 samples.
gene_lengths <- as.data.frame(cbind(rownames(fData(pdxr_expt)),
                                    fData(pdxr_expt)[, c("width")]))
colnames(gene_lengths) <- c("ID", "length")

cog_db <- as.data.frame(cbind(rownames(fData(pdxr_expt)),
                              fData(pdxr_expt)[, c("COGFun")]))
colnames(cog_db) <- c("ID", "GO")
undef_idx <- cog_db[["GO"]] == "undefined"
cog_db <- cog_db[!undef_idx, ]
cog_db <- cog_db %>%
  mutate(GO = strsplit(as.character(GO), "")) %>%
  unnest(GO)

go_db <- as.data.frame(cbind(rownames(fData(pdxr_expt)),
                             fData(pdxr_expt)[, c("GO")]))
colnames(go_db) <- c("ID", "GO")
go_db <- go_db %>%
  mutate(GO = strsplit(as.character(GO), ",")) %>%
  unnest(GO)

I have 36 samples to play with, let us see what they look like.

2.5 Poke expressionSet

pdxr_libsize <- plot_libsize(pdxr_expt)
pdxr_libsize$plot

pdxr_filter_plot <- plot_libsize_prepost(pdxr_expt)
pdxr_filter_plot$count_plot

pdxr_filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.

pdxr_nonzero <- plot_nonzero(pdxr_expt)
## Scale for 'colour' is already present. Adding another scale for 'colour',
## which will replace the existing scale.
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.
pdxr_nonzero$plot
## Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

## awesome, there is a range of ~ 10 genes!

written <- write_expt(pdxr_expt, excel = glue::glue("excel/pdxr_expt-v{ver}.xlsx"))
## Deleting the file excel/pdxr_expt-v202204.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## `geom_smooth()` using formula 'y ~ x'
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
## The following object is masked from 'package:S4Vectors':
## 
##     expand
## 
## Total:12 s
## `geom_smooth()` using formula 'y ~ x'
## 
## Total:12 s

2.6 Quick visualizations

2.6.1 Without considering time

Let us start with some views of the data without thinking about batch effects.

pdxr_norm <- normalize_expt(pdxr_expt, filter=TRUE, norm="quant", convert="cpm", transform="log2")
## Removing 85 low-count genes (1841 remaining).
pdxr_pca <- plot_pca(pdxr_norm)
pdxr_pca$plot

pdxr_heatmap <- plot_disheat(pdxr_norm)
pdxr_heatmap$plot

pdxr_sm <- plot_sm(pdxr_norm)
## Performing correlation.
pdxr_sm$plot

2.6.2 Considering time

Repeat the previous plots, but this time using limma’s batch removal method (which is just a residuals).

pdxr_nb <- normalize_expt(pdxr_expt, filter=TRUE, norm="quant", convert="cpm",
                             transform="log2", batch="limma")
## Removing 85 low-count genes (1841 remaining).
## If you receive a warning: 'NANs produced', one potential reason is that the data was quantile normalized.
## Setting 51 low elements to zero.
## transform_counts: Found 51 values equal to 0, adding 1 to the matrix.
pdxr_nb_pca <- plot_pca(pdxr_nb)
pdxr_nb_pca$plot

pdxr_nb_heatmap <- plot_corheat(pdxr_nb)
pdxr_nb_heatmap$plot

Well, it is pretty clear that time is the dominant factor.

2.7 Differential Expression analyses

I am going to do the DE in 3 separate pieces:

  1. Only compare strains
  2. Only compare times
  3. Compare the concatenation of strains and times.

2.7.1 Strain only comparisons

strain_de <- all_pairwise(pdxr_expt, model_batch=TRUE, filter=TRUE)
## This DE analysis will perform all pairwise comparisons among:
## 
## complement      delta         WT 
##         12         12         12
## This analysis will include a batch factor in the model comprised of:
## 
##  e20m  e60m start 
##    12    12    12
## This will pre-filter the input data using normalize_expt's: TRUE argument.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

strain_keepers <- list(
    "delta_wt" = c("delta", "WT"),
    "complement_wt" = c("complement", "WT"),
    "delta_complement" = c("delta", "complement"))
strain_tables <- combine_de_tables(
    strain_de, keepers = strain_keepers,
    excel = glue::glue("excel/pdxr_strain_tables-v{ver}.xlsx"))
## Deleting the file excel/pdxr_strain_tables-v202204.xlsx before writing the tables.
strain_sig <- extract_significant_genes(
    strain_tables,
    excel = glue::glue("excel/pdxr_strain_sig-v{ver}.xlsx"))
## Deleting the file excel/pdxr_strain_sig-v202204.xlsx before writing the tables.
## Using p column: limma_adjp.
## Using p column: edger_adjp.
## Using p column: deseq_adjp.
## Using p column: ebseq_adjp.
## Using p column: basic_adjp.

2.7.2 Time only comparisons

pdxr_time <- set_expt_conditions(pdxr_expt, fact="growthphase") %>%
  set_expt_batches(fact="genotype")
time_de <- all_pairwise(pdxr_time, model_batch=TRUE)
## This DE analysis will perform all pairwise comparisons among:
## 
##  e20m  e60m start 
##    12    12    12
## This analysis will include a batch factor in the model comprised of:
## 
## complement      delta         WT 
##         12         12         12
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

time_keepers <- list(
    "e20m_start" = c("e20m", "start"),
    "e60m_e20m" = c("e60m", "e20m"),
    "e60m_start" = c("e60m", "start"))
time_tables <- combine_de_tables(
    time_de, keepers = time_keepers,
    excel = glue::glue("excel/pdxr_time_tables-v{ver}.xlsx"))
## Deleting the file excel/pdxr_time_tables-v202204.xlsx before writing the tables.
time_sig <- extract_significant_genes(
    time_tables,
    excel = glue::glue("excel/pdxr_time_sig-v{ver}.xlsx"))
## Deleting the file excel/pdxr_time_sig-v202204.xlsx before writing the tables.
## Using p column: limma_adjp.
## Using p column: edger_adjp.
## Using p column: deseq_adjp.
## Using p column: ebseq_adjp.
## Using p column: basic_adjp.

2.7.3 Combining the two comparisons

combined_factors <- paste0(pData(pdxr_expt)[["genotype"]], "_",
                           pData(pdxr_expt)[["growthphase"]])
combined_expt <- set_expt_conditions(pdxr_expt, fact=combined_factors)

combined_de <- all_pairwise(combined_expt, model_batch="svaseq", filter=TRUE)

combined_keepers <- list(
    "e20m_delta_vs_wt" = c("deltae20m", "WTe20m"),
    "e20m_delta_vs_complement" = c("deltae20m", "complemente20m"),
    "e60m_delta_vs_wt" = c("deltae60m", "WTe60m"),
    "e60m_delta_vs_complement" = c("deltae60m", "complemente60m"),
    "start_delta_vs_wt" = c("deltastart", "WTstart"),
    "start_delta_vs_complement" = c("deltastart", "complementstart"),
    "WT_e20m_vs_start" = c("WTe20m", "WTstart"),
    "delta_e20m_vs_start" = c("deltae20m", "deltastart"),
    "complement_e20m_vs_start" = c("complemente20m", "complementstart"),
    "WT_e60m_vs_start" = c("WTe60m", "WTstart"),
    "delta_e60m_vs_start" = c("deltae60m", "deltastart"),
    "complement_e60m_vs_start" = c("complemente60m", "complementstart"),
    "WT_e60m_vs_e20m" = c("WTe60m", "WTe20m"),
    "delta_e60m_vs_e20m" = c("deltae60m", "deltae20m"),
    "complement_e60m_vs_e20m" = c("complemente60m", "complemente20m"))

combined_tables <- combine_de_tables(
    combined_de, keepers = combined_keepers,
    excel = glue::glue("excel/pdxr_combined_tables-v{ver}.xlsx"))
combined_sig <- extract_significant_genes(
    combined_tables,
    excel = glue::glue("excel/pdxr_combined_sig-v{ver}.xlsx"))

3 Gene Set Enrichment via COGs

Dr. McIver just reminded me of the plot which is of interest for considering the significance of the various categories of gene functions in the data. I think a potentially good version of this would be to use some of the visualizations from clusterprofiler against the COGs as per:

https://yulab-smu.top/biomedical-knowledge-mining-book/enrichplot.html

In order to get an initial set to test, I will try some quick and dirty goseq with the COG categories.

time_e20start_up <- time_sig[["deseq"]][["ups"]][["e20m_start"]]
e20start_up_goseq_cog <- simple_goseq(time_e20start_up, go_db=cog_db, length_db=gene_lengths,
                                      expand_categories=FALSE)
## Found 104 go_db genes and 170 length_db genes out of 170.
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category"                 "over_represented_pvalue" 
## [3] "under_represented_pvalue" "numDEInCat"              
## [5] "numInCat"                 "qvalue"
## Error in `[.data.frame`(plotting, , c("term", "over_represented_pvalue", : undefined columns selected
e20start_up_goseq_go <- simple_goseq(time_e20start_up, go_db=go_db, length_db=gene_lengths)
## Found 170 go_db genes and 170 length_db genes out of 170.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category"                 "over_represented_pvalue" 
## [3] "under_represented_pvalue" "numDEInCat"              
## [5] "numInCat"                 "term"                    
## [7] "ontology"                 "qvalue"
## Error in layer(data = data, mapping = mapping, stat = stat, geom = GeomText, : object 'test_color' not found
e20start_up_goseq_go$pvalue_plots$mfp_plot_over
## Error in eval(expr, envir, enclos): object 'e20start_up_goseq_go' not found
e20start_up_goseq_go$pvalue_plots$bpp_plot_over
## Error in eval(expr, envir, enclos): object 'e20start_up_goseq_go' not found

4 Make a circos picture

Work on making a pretty picture, there are kind of a lot of potential contrasts, so lets just start with one.

circos_cfg <- circos_prefix(fData(pdxr_expt), name="pdxr", chr_column="seqnames", start_column="start.x",
                            stop_column = "end", strand_column="strand.x", cog_column = "COGFun")
## This assumes you have a colors.conf in circos/colors/ and fonts.conf in circos/fonts/
## It also assumes you have conf/ideogram.conf, conf/ticks.conf, and conf/housekeeping.conf
## It will write circos/conf/pdxr.conf with a reasonable first approximation config file.
## Setting 86 undefined entries to the plus strand.
## Warning in circos_prefix(fData(pdxr_expt), name = "pdxr", chr_column =
## "seqnames", : NAs introduced by coercion

## Warning in circos_prefix(fData(pdxr_expt), name = "pdxr", chr_column =
## "seqnames", : NAs introduced by coercion
## Wrote karyotype to circos/conf/ideograms/pdxr.conf
## This should match the ideogram= line in pdxr.conf
## Wrote ticks to circos/conf/ticks_pdxr.conf
kary <- circos_karyotype(circos_cfg, fasta = "reference/spyogenes_5005.fasta")
## Wrote karyotype to circos/conf/karyotypes/pdxr.conf
## This should match the karyotype= line in pdxr.conf
plus_minus <- circos_plus_minus(circos_cfg, width = 0.06, thickness = 40,
                                url_string = "http://www.microbesonline.org/cgi-bin/fetchLocus.cgi?locus=[id]")
## Writing data file: circos/data/pdxr_plus_go.txt with the + strand GO data.
## Writing data file: circos/data/pdxr_minus_go.txt with the - strand GO data.
## Wrote the +/- config files.  Appending their inclusion to the master file.
## Returning the inner width: 0.88.  Use it as the outer for the next ring.
exp_delta_vs_wt_hist <- circos_hist(circos_cfg, combined_tables, tablename="start_delta_vs_wt",
                                    colname="deseq_logfc", basename="start_deltawt",
                                    outer=plus_minus)
## Error in "combined_de" %in% class(input): object 'combined_tables' not found
cjb_suffix <- circos_suffix(circos_cfg)
made <- circos_make(circos_cfg, target="pdxr")

circos/pdxr.png

if (!isTRUE(get0("skip_load"))) {
  pander::pander(sessionInfo())
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  this_save <- paste0(gsub(pattern = "\\.Rmd", replace = "", x = rmd_file), "-v", ver, ".rda.xz")
  message(paste0("Saving to ", this_save))
  tmp <- sm(saveme(filename = this_save))
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 605cc89b5f1cadea6923b53ac71e234ba0181fe7
## This is hpgltools commit: Wed Aug 10 22:39:40 2022 -0400: 605cc89b5f1cadea6923b53ac71e234ba0181fe7
## Saving to index_pdxR-v202204.rda.xz
LS0tCnRpdGxlOiAiUy5weW9nZW5lcyA1NDQ4IHJuYXNlcSBjb21wYXJpbmcgcGR4UiBzdHJhaW5zIGFjcm9zcyB0aW1lLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKICB9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gOTAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSA4LAogICAgICAgICAgICAgICAgICAgICAgZHBpID0gOTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzID0gNCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwKSkKc2V0LnNlZWQoMSkKdmVyIDwtICIyMDIyMDQiCnJtZF9maWxlIDwtICJpbmRleF9wZHhSLlJtZCIKYGBgCgojIEltcG9ydGFudCBub3RlCgpJIGNvcGllZCBteSBpbmRleF9yb2ZBIGFuZCBqdXN0IHBlcmZvcm1lZCByZXBsYWNlLXN0cmluZyBvbiBpdCBmb3IgdGhlIHRpbWVzIGFuZCBzdHJhaW5zOgoKMS4gIHMvcmV2ZXJ0L2NvbXBsZW1lbnQvZwoyLiAgcy90cmFuc2l0aW9uL3N0YXJ0L2cKMy4gIHMvZXhwb25lbnRpYWwvZTIwbS9nCjQuICBzL3N0YXRpb25hcnkvZTYwbS9nCgojIFMucHlvZ2VuZXMgNTQ0OCBwZHhSIFJOQVNlcSB2ZXJzaW9uOiBgciB2ZXJgCgojIyBQcmVwcm9jZXNzaW5nCgpJIHVzZWQgbXkgY3lvYSB0b29sIHRvIHByb2Nlc3MgdGhlc2Ugc2FtcGxlcyBieSBkb2luZyB0aGUgZm9sbG93aW5nOgoKMS4gIENvcHlpbmcgdGhlIGRhdGEgZnJvbSB0aGUgc2VxdWVuY2VyIGludG8gdGhlIGRpcmVjdG9yeSAncHJlcHJvY2Vzc2luZy8nCjIuICBVc2VkIGEgc2xpZ2h0bHkgaW52b2x2ZWQgc2hlbGwgY29tbWFuZCB0byBjcmVhdGUgYSBkaXJlY3RvcnkgZm9yCiAgICBlYWNoIHNhbXBsZSBhbmQgY29weSB0aGUgcmVhZHMgZm9yIGl0IHRvIHRoZSAndW5wcm9jZXNzZWQvJwogICAgc3ViZGlyZWN0b3J5IHdpdGhpbiBpdC4KMy4gIGludm9rZWQgdGhlIGZvbGxvd2luZzoKCmBgYHtiYXNoLCBldmFsPUZBTFNFfQpjZCBwcmVwcm9jZXNzaW5nCnN0YXJ0PSQocHdkKQpmb3IgaSBpbiAkKC9iaW4vbHMgLWQgLi8qKQpkbwogIGNkICRpCiAgcm0gLXJmIG91dHB1dHMgc2NyaXB0cwogIGN5b2EgLS10YXNrIHBpcGUgLS1tZXRob2QgcHJuYXMgLS1zcGVjaWVzIHNweW9nZW5lc181MDA1IFwKICAgICAgIC0tZ2ZmX3R5cGUgZ2VuZSAtLWdmZl90YWcgbG9jdXNfdGFnIFwKICAgICAgIC0taW5wdXQgJCgvYmluL2xzIHVucHJvY2Vzc2VkLyogfCB0ciAnXG4nICc6JyB8IHNlZCAncy86JC8vZycpCiAgY2QgJHN0YXJ0CmRvbmUKYGBgCgpUaGUgYWJvdmUgZm9yIGxvb3AgZ29lcyBpbnRvIGVhY2ggc2FtcGxlIGFuZCBkb2VzIHRoZSBmb2xsb3dpbmc6CgoxLiAgVHJpbXMgdGhlIGRhdGEsIGhlYXZpbHkgY29tcHJlc3NlcyB0aGUgb3V0cHV0cy4KMi4gIFJ1bnMgZmFzdHFjCjMuICBSdW5zIGhpc2F0MiB1c2luZyBteSBzcHlvZ2VuZXNfNTAwNSBpbmRpY2VzLgo0LiAgQ29udmVydHMgdGhlIHNhbSBhbGlnbm1lbnQgdG8gc29ydGVkL2luZGV4ZWQgYmFtLgo1LiAgTWFrZXMgYSBjb3VwbGUgb2YgZXh0cmEgY29waWVzIG9mIGl0IHdpdGggc29tZSBmaWx0ZXJzLgo2LiAgQ29tcHJlc3NlcyB0aGUgYWxpZ25lZC91bmFsaWduZWQgcmVhZHMuCjcuICBSdW5zIGh0c2VxLWNvdW50IG9uIHRoZSBhbGlnbm1lbnRzIHRvIGNvdW50IHJlYWRzL2dlbmUuCgogIE5vdGUgdGhlIGZvbGxvd2luZyBzdGVwcyB3ZXJlIG5vdCBhY3R1YWxseSBydW4gYmVjYXVzZSBJIGhhZCBhCiAgc3BlZWxpbmcgZXJyb3IuICBCdXQgc2luY2UgdGhleSBhcmUgbm90IG5lY2Vzc2FyeSBmb3IgdGhlIGV4cGxpY2l0bHkKICBSTkFTZXEgYW5hbHlzZXMgSSBmaXJzdCB3YW50IHRvIGRvLCBJIGlnbm9yZWQgaXQuICBJIGFtIGN1cmlvdXMKICB0aG91Z2ggdG8gc2VlIGlmIHRoZXJlIGFyZSBvdGhlciBtdXRhdGlvbnMgaW4gdGhlc2Ugc3RyYWlucywgc28gSQogIHdpbGwgbGlrZWx5IHJ1biB0aG9zZSBwb3J0aW9ucyBtYW51YWxseS4KCjguICBSdW5zIGZyZWViYXllcyBvbiB0aGUgYWxpZ25tZW50cyB0byBsb29rIGZvciB2YXJpYW50cy4KOS4gIFNvcnRzL2NvbXByZXNzZXMgdGhlIGZyZWViYXllcyBvdXRwdXQuCjEwLiBEb2VzIHNvbWUgcGFyc2luZyBvZiB0aGUgZnJlZWJheWVzIG91dHB1dCBhbmQgcHJvdmlkZXMgc29tZSB0YWJsZXMKICAgIGFib3V0IHdoZXJlIG11dGF0aW9ucyB3ZXJlIG9ic2VydmVkLgoKIyMgQ29sbGVjdCBhbm5vdGF0aW9uIGluZm9ybWF0aW9uCgpTYW1lIHR3byBwcmltYXJ5IGFubm90YXRpb24gc291cmNlcywgdGhlIGdmZiBmaWxlIHVzZWQgZm9yIG1hcHBpbmcvY291bnRpbmcsCmFuZCBtaWNyb2Jlc29ubGluZS5vcmcuICBOb3RlIHRoYXQgc2luY2UgSSBtb3ZlZCB0byBqdXN0IGRvd25sb2FkaW5nIHRoZQptYXRlcmlhbCBmcm9tIHRoZSB3ZWIgaW50ZXJmYWNlLCBJIG5vIGxvbmdlciBoYXZlIGEgaGFuZHkgbWV0aG9kIHRvIGdldCB0aGUKdGF4b24gSUQsIHNvIEkgZ28gdGhlcmUgYW5kIGh1bnQgZG93biB0aGUgdGF4SWQgbWFudWFsbHkuCgpgYGB7ciBhbm5vdGF0aW9ufQpnZmZfYW5ub3QgPC0gbG9hZF9nZmZfYW5ub3RhdGlvbnMoInJlZmVyZW5jZS9zcHlvZ2VuZXNfNTAwNS5nZmYiLCB0eXBlID0gIkNEUyIpCnJvd25hbWVzKGdmZl9hbm5vdCkgPC0gZ2ZmX2Fubm90W1sibG9jdXNfdGFnIl1dCmhlYWQoZ2ZmX2Fubm90KQoKbWljcm9iZXNfYW5ub3QgPC0gbG9hZF9taWNyb2Jlc29ubGluZV9hbm5vdGF0aW9ucyhzcGVjaWVzPSI1MDA1IikKbWljcm9iZXNfYW5ub3QgPC0gYXMuZGF0YS5mcmFtZShtaWNyb2Jlc19hbm5vdCkKcm93bmFtZXMobWljcm9iZXNfYW5ub3QpIDwtIG1ha2UubmFtZXMoZ3N1Yih4PW1pY3JvYmVzX2Fubm90W1sic3lzTmFtZSJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJTcHlfIiwgcmVwbGFjZW1lbnQ9IlNweSIpLCB1bmlxdWU9VFJVRSkKCmJvdGhfYW5ub3QgPC0gbWVyZ2UoZ2ZmX2Fubm90LCBtaWNyb2Jlc19hbm5vdCwgYnk9InJvdy5uYW1lcyIsIGFsbC55PVRSVUUpCnJvd25hbWVzKGJvdGhfYW5ub3QpIDwtIGJvdGhfYW5ub3RbWyJSb3cubmFtZXMiXV0KYm90aF9hbm5vdFtbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCmBgYAoKIyMgUmVydW5uaW5nIG15IGZhc3RhMzYgbWFwcGVyIGFjcm9zcyBzdHJhaW5zCgpPbmNlIHVwb24gYSB0aW1lIEkgd3JvdGUgYSBsaXR0bGUgdG9vbCB0byBjb21wYXJlIGNsb3NlbHkKc3BlY2llcy9zdHJhaW5zLiAgSXQgaXMgZXNzZW50aWFsbHkgYSBwb29yLW1hbidzIG9ydGhvbG9nIHNlYXJjaC4gIEl0CmhhcyBiZWVuIGEgdmVyeSBsb25nIHRpbWUgc2luY2UgbGFzdCBJIHVzZWQgaXQsIGFuZCBpdCByZXF1aXJlZCBzb21lCm1vZGlmaWNhdGlvbnMgaW4gb3JkZXIgdG8gd29yayBwcm9wZXJseS4gIFRoZSBtb3N0IG5vdGFibGUgcHJvYmxlbSBpcwp0aGF0IHRoZSBwYXRobmFtZXMgaXQgdXNlcyBhcmUgdG9vIGxvbmcgZm9yIGZhc3RhMzYuICBJIHNob3J0ZW5lZCB0aGVtCmFuZCBmaXhlZCBhIGNvdXBsZSBvZiBvbGQgZXJyb3JzIGFuZCBpdCBhcHBlYXJzIHRvIHdvcmsgYWdhaW4uCgpgYGB7ciBzaW5nbGVfbXVsdGl9CnNpbmdsZV9oaXRzIDwtIHJlYWRyOjpyZWFkX3Rzdigic2luZ2xlX211bHRpL291dHB1dHMvZmFzdGFfc3B5b2dlbmVzXzU0NDhfY2RzX3NweW9nZW5lc181MDA1X2Nkcy9zcHlvZ2VuZXNfNTQ0OF9jZHNfc2luZ2xlcy50eHQiKQpjb2xuYW1lcyhzaW5nbGVfaGl0cykgPC0gYygiZnJvbSIsICJ0byIpCnNpbmdsZV9oaXRzW1sidG8iXV0gPC0gZ3N1YihwYXR0ZXJuPSIoXi4qPyk6LiokIiwgcmVwbGFjZW1lbnQ9IlxcMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PXNpbmdsZV9oaXRzW1sidG8iXV0sIHBlcmw9VFJVRSkKIyMgVGhlIGdmZiBhbm5vdGF0aW9uIGhhcyB0aGUgcHJvdGVpbl9pZCBjb2x1bW4gbWF0Y2hpbmcgdGhpcyBjZHMgZW50cnkuCgpzaW5nbGVfYm90aCA8LSBtZXJnZShtZ2FzX2Fubm90LCBzaW5nbGVfaGl0cywgYnkueD0icHJvdGVpbl9pZCIsIGJ5Lnk9ImZyb20iLCBhbGwueD1UUlVFKQpzaW5nbGVfYm90aCA8LSBtZXJnZShzaW5nbGVfYm90aCwgcmVmX2dmZl9hbm5vdCwgYnkueD0idG8iLCBieS55PSJwcm90ZWluX2lkIiwgYWxsLng9VFJVRSkKCiMjIE5vdyBwaWNrIHVwIHRoZSBtaXNzaW5nIG9sZF9sb2N1c190YWdzIGFuZCBwdXQgaW4gdGhlIDU0NDggSURzCm1pc3NpbmdfaWRzIDwtIGlzLm5hKHNpbmdsZV9ib3RoW1sib2xkX2xvY3VzX3RhZyJdXSkKbmV3X2lkcyA8LSBzaW5nbGVfYm90aFttaXNzaW5nX2lkcywgImxvY3VzX3RhZy54Il0Kc2luZ2xlX2JvdGhbbWlzc2luZ19pZHMsICJvbGRfbG9jdXNfdGFnIl0gPC0gbmV3X2lkcwoKc2luZ2xlX2JvdGggPC0gbWVyZ2Uoc2luZ2xlX2JvdGgsIG1pY3JvYmVzX2Fubm90LCBieS54PSJvbGRfbG9jdXNfdGFnIiwgYnkueT0ic3lzTmFtZSIsIGFsbC54PVRSVUUpCnJvd25hbWVzKHNpbmdsZV9ib3RoKSA8LSBtYWtlLm5hbWVzKHNpbmdsZV9ib3RoW1siZ2VuZV9pZCJdXSwgdW5pcXVlPVRSVUUpCmBgYAoKIyMgQ3JlYXRlIGV4cHJlc3Npb25TZXQKCk5vdGUgdGhhdCBJIGRpZCB0aGUgZm9sbG93aW5nIHRvIHRoZSBzYW1wbGUgc2hlZXQgcHJvdmlkZWQgYnkKRHIuIE1jSXZlcjoKCjEuICBDaGFuZ2VkIHRoZSBkUF9SMjBfNCBzYW1wbGUgdG8gZFBfUjIwXzIgKFRoZSBvcmlnaW5hbCBzYW1wbGUgbmFtZQogICAgaXMgc3RpbGwgdGhlcmUgYXJlIHRoZSBvcmlnaW5hbCBjb2x1bW4pLgoyLiAgQWRkZWQgY29sdW1ucyBhdCB0aGUgZW5kIGNvbnRhaW5pbmcgdGhlIGNvdW50IHRhYmxlIGxvY2F0aW9ucy4KMy4gIEFkZGVkIGNvbHVtbnMgJ3Nob3J0X21lZGlhJywgJ2dyb3d0aF9waGFzZScsICdnZW5vdHlwZScgd2hpY2gKICAgIGhvcGVmdWxseSBjb250YWluIHRoZSByZWxldmFudCBtZXRhZGF0YSBleHRyYWN0ZWQgZnJvbSB0aGUgc2FtcGxlCiAgICBkZXNjcmlwdGlvbnMuCjQuICBBZGRlZCBhIGNvbHVtbiAnRXhwZXJpbWVudCcgd2hpY2ggaXMgZWl0aGVyICdyb2ZBJyBvciAncGR4UicuCgpgYGB7ciBleHB0fQpwZHhyX2V4cHQgPC0gY3JlYXRlX2V4cHQobWV0YWRhdGEgPSAic2FtcGxlX3NoZWV0cy9hbGxfc2FtcGxlcy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gYm90aF9hbm5vdCwgZmlsZV9jb2x1bW4gPSAic3B5b2dlbmVzNTAwNWdlbmVjb3VudHMiKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9ImV4cGVyaW1lbnQ9PSdwZHhSJyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdD0iZ2Vub3R5cGUiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9Imdyb3d0aHBoYXNlIikKYGBgCgpgYGB7ciBnb3NlcV9kYXRhfQpnZW5lX2xlbmd0aHMgPC0gYXMuZGF0YS5mcmFtZShjYmluZChyb3duYW1lcyhmRGF0YShwZHhyX2V4cHQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZkRhdGEocGR4cl9leHB0KVssIGMoIndpZHRoIildKSkKY29sbmFtZXMoZ2VuZV9sZW5ndGhzKSA8LSBjKCJJRCIsICJsZW5ndGgiKQoKY29nX2RiIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQocm93bmFtZXMoZkRhdGEocGR4cl9leHB0KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZEYXRhKHBkeHJfZXhwdClbLCBjKCJDT0dGdW4iKV0pKQpjb2xuYW1lcyhjb2dfZGIpIDwtIGMoIklEIiwgIkdPIikKdW5kZWZfaWR4IDwtIGNvZ19kYltbIkdPIl1dID09ICJ1bmRlZmluZWQiCmNvZ19kYiA8LSBjb2dfZGJbIXVuZGVmX2lkeCwgXQpjb2dfZGIgPC0gY29nX2RiICU+JQogIG11dGF0ZShHTyA9IHN0cnNwbGl0KGFzLmNoYXJhY3RlcihHTyksICIiKSkgJT4lCiAgdW5uZXN0KEdPKQoKZ29fZGIgPC0gYXMuZGF0YS5mcmFtZShjYmluZChyb3duYW1lcyhmRGF0YShwZHhyX2V4cHQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmRGF0YShwZHhyX2V4cHQpWywgYygiR08iKV0pKQpjb2xuYW1lcyhnb19kYikgPC0gYygiSUQiLCAiR08iKQpnb19kYiA8LSBnb19kYiAlPiUKICBtdXRhdGUoR08gPSBzdHJzcGxpdChhcy5jaGFyYWN0ZXIoR08pLCAiLCIpKSAlPiUKICB1bm5lc3QoR08pCmBgYAoKCkkgaGF2ZSAzNiBzYW1wbGVzIHRvIHBsYXkgd2l0aCwgbGV0IHVzIHNlZSB3aGF0IHRoZXkgbG9vayBsaWtlLgoKIyMgUG9rZSBleHByZXNzaW9uU2V0CgpgYGB7ciBwb2tlfQpwZHhyX2xpYnNpemUgPC0gcGxvdF9saWJzaXplKHBkeHJfZXhwdCkKcGR4cl9saWJzaXplJHBsb3QKCnBkeHJfZmlsdGVyX3Bsb3QgPC0gcGxvdF9saWJzaXplX3ByZXBvc3QocGR4cl9leHB0KQpwZHhyX2ZpbHRlcl9wbG90JGNvdW50X3Bsb3QKcGR4cl9maWx0ZXJfcGxvdCRsb3dnZW5lX3Bsb3QKCnBkeHJfbm9uemVybyA8LSBwbG90X25vbnplcm8ocGR4cl9leHB0KQpwZHhyX25vbnplcm8kcGxvdAojIyBhd2Vzb21lLCB0aGVyZSBpcyBhIHJhbmdlIG9mIH4gMTAgZ2VuZXMhCgp3cml0dGVuIDwtIHdyaXRlX2V4cHQocGR4cl9leHB0LCBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3BkeHJfZXhwdC12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIFF1aWNrIHZpc3VhbGl6YXRpb25zCgojIyMgV2l0aG91dCBjb25zaWRlcmluZyB0aW1lCgpMZXQgdXMgc3RhcnQgd2l0aCBzb21lIHZpZXdzIG9mIHRoZSBkYXRhIHdpdGhvdXQgdGhpbmtpbmcgYWJvdXQgYmF0Y2ggZWZmZWN0cy4KCmBgYHtyIHZpZXdfbm9iYXRjaH0KcGR4cl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHBkeHJfZXhwdCwgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIikKcGR4cl9wY2EgPC0gcGxvdF9wY2EocGR4cl9ub3JtKQpwZHhyX3BjYSRwbG90CgpwZHhyX2hlYXRtYXAgPC0gcGxvdF9kaXNoZWF0KHBkeHJfbm9ybSkKcGR4cl9oZWF0bWFwJHBsb3QKCnBkeHJfc20gPC0gcGxvdF9zbShwZHhyX25vcm0pCnBkeHJfc20kcGxvdApgYGAKCiMjIyBDb25zaWRlcmluZyB0aW1lCgpSZXBlYXQgdGhlIHByZXZpb3VzIHBsb3RzLCBidXQgdGhpcyB0aW1lIHVzaW5nIGxpbW1hJ3MgYmF0Y2ggcmVtb3ZhbAptZXRob2QgKHdoaWNoIGlzIGp1c3QgYSByZXNpZHVhbHMpLgoKYGBge3IgbmJfdmlld30KcGR4cl9uYiA8LSBub3JtYWxpemVfZXhwdChwZHhyX2V4cHQsIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2g9ImxpbW1hIikKcGR4cl9uYl9wY2EgPC0gcGxvdF9wY2EocGR4cl9uYikKcGR4cl9uYl9wY2EkcGxvdAoKcGR4cl9uYl9oZWF0bWFwIDwtIHBsb3RfY29yaGVhdChwZHhyX25iKQpwZHhyX25iX2hlYXRtYXAkcGxvdApgYGAKCldlbGwsIGl0IGlzIHByZXR0eSBjbGVhciB0aGF0IHRpbWUgaXMgdGhlIGRvbWluYW50IGZhY3Rvci4KCiMjIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIGFuYWx5c2VzCgpJIGFtIGdvaW5nIHRvIGRvIHRoZSBERSBpbiAzIHNlcGFyYXRlIHBpZWNlczoKCjEuICBPbmx5IGNvbXBhcmUgc3RyYWlucwoyLiAgT25seSBjb21wYXJlIHRpbWVzCjMuICBDb21wYXJlIHRoZSBjb25jYXRlbmF0aW9uIG9mIHN0cmFpbnMgYW5kIHRpbWVzLgoKIyMjIFN0cmFpbiBvbmx5IGNvbXBhcmlzb25zCgpgYGB7ciBwYWlyd2lzZV9zdHJhaW59CnN0cmFpbl9kZSA8LSBhbGxfcGFpcndpc2UocGR4cl9leHB0LCBtb2RlbF9iYXRjaD1UUlVFLCBmaWx0ZXI9VFJVRSkKc3RyYWluX2tlZXBlcnMgPC0gbGlzdCgKICAgICJkZWx0YV93dCIgPSBjKCJkZWx0YSIsICJXVCIpLAogICAgImNvbXBsZW1lbnRfd3QiID0gYygiY29tcGxlbWVudCIsICJXVCIpLAogICAgImRlbHRhX2NvbXBsZW1lbnQiID0gYygiZGVsdGEiLCAiY29tcGxlbWVudCIpKQpzdHJhaW5fdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgc3RyYWluX2RlLCBrZWVwZXJzID0gc3RyYWluX2tlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3BkeHJfc3RyYWluX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpzdHJhaW5fc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBzdHJhaW5fdGFibGVzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9wZHhyX3N0cmFpbl9zaWctdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMgVGltZSBvbmx5IGNvbXBhcmlzb25zCgpgYGB7ciBwYWlyd2lzZV90aW1lfQpwZHhyX3RpbWUgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhwZHhyX2V4cHQsIGZhY3Q9Imdyb3d0aHBoYXNlIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0PSJnZW5vdHlwZSIpCnRpbWVfZGUgPC0gYWxsX3BhaXJ3aXNlKHBkeHJfdGltZSwgbW9kZWxfYmF0Y2g9VFJVRSkKdGltZV9rZWVwZXJzIDwtIGxpc3QoCiAgICAiZTIwbV9zdGFydCIgPSBjKCJlMjBtIiwgInN0YXJ0IiksCiAgICAiZTYwbV9lMjBtIiA9IGMoImU2MG0iLCAiZTIwbSIpLAogICAgImU2MG1fc3RhcnQiID0gYygiZTYwbSIsICJzdGFydCIpKQp0aW1lX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIHRpbWVfZGUsIGtlZXBlcnMgPSB0aW1lX2tlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3BkeHJfdGltZV90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKdGltZV9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIHRpbWVfdGFibGVzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9wZHhyX3RpbWVfc2lnLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIENvbWJpbmluZyB0aGUgdHdvIGNvbXBhcmlzb25zCgpgYGB7ciBjb21iaW5lZF9kZSwgZXZhbD1GQUxTRX0KY29tYmluZWRfZmFjdG9ycyA8LSBwYXN0ZTAocERhdGEocGR4cl9leHB0KVtbImdlbm90eXBlIl1dLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBEYXRhKHBkeHJfZXhwdClbWyJncm93dGhwaGFzZSJdXSkKY29tYmluZWRfZXhwdCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHBkeHJfZXhwdCwgZmFjdD1jb21iaW5lZF9mYWN0b3JzKQoKY29tYmluZWRfZGUgPC0gYWxsX3BhaXJ3aXNlKGNvbWJpbmVkX2V4cHQsIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKCmNvbWJpbmVkX2tlZXBlcnMgPC0gbGlzdCgKICAgICJlMjBtX2RlbHRhX3ZzX3d0IiA9IGMoImRlbHRhZTIwbSIsICJXVGUyMG0iKSwKICAgICJlMjBtX2RlbHRhX3ZzX2NvbXBsZW1lbnQiID0gYygiZGVsdGFlMjBtIiwgImNvbXBsZW1lbnRlMjBtIiksCiAgICAiZTYwbV9kZWx0YV92c193dCIgPSBjKCJkZWx0YWU2MG0iLCAiV1RlNjBtIiksCiAgICAiZTYwbV9kZWx0YV92c19jb21wbGVtZW50IiA9IGMoImRlbHRhZTYwbSIsICJjb21wbGVtZW50ZTYwbSIpLAogICAgInN0YXJ0X2RlbHRhX3ZzX3d0IiA9IGMoImRlbHRhc3RhcnQiLCAiV1RzdGFydCIpLAogICAgInN0YXJ0X2RlbHRhX3ZzX2NvbXBsZW1lbnQiID0gYygiZGVsdGFzdGFydCIsICJjb21wbGVtZW50c3RhcnQiKSwKICAgICJXVF9lMjBtX3ZzX3N0YXJ0IiA9IGMoIldUZTIwbSIsICJXVHN0YXJ0IiksCiAgICAiZGVsdGFfZTIwbV92c19zdGFydCIgPSBjKCJkZWx0YWUyMG0iLCAiZGVsdGFzdGFydCIpLAogICAgImNvbXBsZW1lbnRfZTIwbV92c19zdGFydCIgPSBjKCJjb21wbGVtZW50ZTIwbSIsICJjb21wbGVtZW50c3RhcnQiKSwKICAgICJXVF9lNjBtX3ZzX3N0YXJ0IiA9IGMoIldUZTYwbSIsICJXVHN0YXJ0IiksCiAgICAiZGVsdGFfZTYwbV92c19zdGFydCIgPSBjKCJkZWx0YWU2MG0iLCAiZGVsdGFzdGFydCIpLAogICAgImNvbXBsZW1lbnRfZTYwbV92c19zdGFydCIgPSBjKCJjb21wbGVtZW50ZTYwbSIsICJjb21wbGVtZW50c3RhcnQiKSwKICAgICJXVF9lNjBtX3ZzX2UyMG0iID0gYygiV1RlNjBtIiwgIldUZTIwbSIpLAogICAgImRlbHRhX2U2MG1fdnNfZTIwbSIgPSBjKCJkZWx0YWU2MG0iLCAiZGVsdGFlMjBtIiksCiAgICAiY29tcGxlbWVudF9lNjBtX3ZzX2UyMG0iID0gYygiY29tcGxlbWVudGU2MG0iLCAiY29tcGxlbWVudGUyMG0iKSkKCmNvbWJpbmVkX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIGNvbWJpbmVkX2RlLCBrZWVwZXJzID0gY29tYmluZWRfa2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvcGR4cl9jb21iaW5lZF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKY29tYmluZWRfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBjb21iaW5lZF90YWJsZXMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3BkeHJfY29tYmluZWRfc2lnLXZ7dmVyfS54bHN4IikpCmBgYAoKIyBHZW5lIFNldCBFbnJpY2htZW50IHZpYSBDT0dzCgpEci4gTWNJdmVyIGp1c3QgcmVtaW5kZWQgbWUgb2YgdGhlIHBsb3Qgd2hpY2ggaXMgb2YgaW50ZXJlc3QgZm9yCmNvbnNpZGVyaW5nIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhlIHZhcmlvdXMgY2F0ZWdvcmllcyBvZiBnZW5lCmZ1bmN0aW9ucyBpbiB0aGUgZGF0YS4gIEkgdGhpbmsgYSBwb3RlbnRpYWxseSBnb29kIHZlcnNpb24gb2YgdGhpcwp3b3VsZCBiZSB0byB1c2Ugc29tZSBvZiB0aGUgdmlzdWFsaXphdGlvbnMgZnJvbSBjbHVzdGVycHJvZmlsZXIKYWdhaW5zdCB0aGUgQ09HcyBhcyBwZXI6CgpodHRwczovL3l1bGFiLXNtdS50b3AvYmlvbWVkaWNhbC1rbm93bGVkZ2UtbWluaW5nLWJvb2svZW5yaWNocGxvdC5odG1sCgpJbiBvcmRlciB0byBnZXQgYW4gaW5pdGlhbCBzZXQgdG8gdGVzdCwgSSB3aWxsIHRyeSBzb21lIHF1aWNrIGFuZApkaXJ0eSBnb3NlcSB3aXRoIHRoZSBDT0cgY2F0ZWdvcmllcy4KCmBgYHtyIGNvZ19nc2VhfQp0aW1lX2UyMHN0YXJ0X3VwIDwtIHRpbWVfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJlMjBtX3N0YXJ0Il1dCmUyMHN0YXJ0X3VwX2dvc2VxX2NvZyA8LSBzaW1wbGVfZ29zZXEodGltZV9lMjBzdGFydF91cCwgZ29fZGI9Y29nX2RiLCBsZW5ndGhfZGI9Z2VuZV9sZW5ndGhzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGFuZF9jYXRlZ29yaWVzPUZBTFNFKQoKZTIwc3RhcnRfdXBfZ29zZXFfZ28gPC0gc2ltcGxlX2dvc2VxKHRpbWVfZTIwc3RhcnRfdXAsIGdvX2RiPWdvX2RiLCBsZW5ndGhfZGI9Z2VuZV9sZW5ndGhzKQplMjBzdGFydF91cF9nb3NlcV9nbyRwdmFsdWVfcGxvdHMkbWZwX3Bsb3Rfb3ZlcgplMjBzdGFydF91cF9nb3NlcV9nbyRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3ZlcgpgYGAKCiMgTWFrZSBhIGNpcmNvcyBwaWN0dXJlCgpXb3JrIG9uIG1ha2luZyBhIHByZXR0eSBwaWN0dXJlLCB0aGVyZSBhcmUga2luZCBvZiBhIGxvdCBvZiBwb3RlbnRpYWwgY29udHJhc3RzLCBzbyBsZXRzIGp1c3QKc3RhcnQgd2l0aCBvbmUuCgpgYGB7ciBjaXJjb3NfcmVzdWx0fQpjaXJjb3NfY2ZnIDwtIGNpcmNvc19wcmVmaXgoZkRhdGEocGR4cl9leHB0KSwgbmFtZT0icGR4ciIsIGNocl9jb2x1bW49InNlcW5hbWVzIiwgc3RhcnRfY29sdW1uPSJzdGFydC54IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3BfY29sdW1uID0gImVuZCIsIHN0cmFuZF9jb2x1bW49InN0cmFuZC54IiwgY29nX2NvbHVtbiA9ICJDT0dGdW4iKQprYXJ5IDwtIGNpcmNvc19rYXJ5b3R5cGUoY2lyY29zX2NmZywgZmFzdGEgPSAicmVmZXJlbmNlL3NweW9nZW5lc181MDA1LmZhc3RhIikKcGx1c19taW51cyA8LSBjaXJjb3NfcGx1c19taW51cyhjaXJjb3NfY2ZnLCB3aWR0aCA9IDAuMDYsIHRoaWNrbmVzcyA9IDQwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybF9zdHJpbmcgPSAiaHR0cDovL3d3dy5taWNyb2Jlc29ubGluZS5vcmcvY2dpLWJpbi9mZXRjaExvY3VzLmNnaT9sb2N1cz1baWRdIikKZXhwX2RlbHRhX3ZzX3d0X2hpc3QgPC0gY2lyY29zX2hpc3QoY2lyY29zX2NmZywgY29tYmluZWRfdGFibGVzLCB0YWJsZW5hbWU9InN0YXJ0X2RlbHRhX3ZzX3d0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZT0iZGVzZXFfbG9nZmMiLCBiYXNlbmFtZT0ic3RhcnRfZGVsdGF3dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGVyPXBsdXNfbWludXMpCmNqYl9zdWZmaXggPC0gY2lyY29zX3N1ZmZpeChjaXJjb3NfY2ZnKQptYWRlIDwtIGNpcmNvc19tYWtlKGNpcmNvc19jZmcsIHRhcmdldD0icGR4ciIpCmBgYAoKW2NpcmNvcy9wZHhyLnBuZ10oY2lyY29zL3BkeHIucG5nKQoKCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIiIsIHggPSBybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lID0gdGhpc19zYXZlKSkKfQpgYGAK