1 Introduction

This project seeks to understand the effects of deleting/complementing pknF in Mtb. I cannot honestly say I know anything about the biology involved except the bits from the review Volker kindly sent me.

pknF is one of the surprisingly large number of serine threonine protein kinases in Mtb. Most bacteria have only a couple/few of these, but Mtb has 11, and uses them with similar frequency to the two component systems in order to respond to its changing environment during infection (I assume, I have not gotten that far in the review yet). In previous experiments performed by people in Volker’s lab, a deletion of this particular STPK causes a much more virulent phenotype during mouse infection.

2 Preprocessing

I wrote a quick sample sheet for these 9 samples and will use my cyoa toy to perform the various tasks to process the data.

2.1 What annotations do I have?

I am assuming the most appropriate annotations come from microbesonline? Let us check real quick. I should probably go back through my old logs to answer these questions.

annot <- load_microbesonline_annotations("CDC1551")
## Found 1 entry.
## Mycobacterium tuberculosis CDC1551Actinobacteriayes2007-05-08yes10429383331
## The species being downloaded is: Mycobacterium tuberculosis CDC1551
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=83331;export=tab
annot <- as.data.frame(annot)
rownames(annot) <- make.names(annot[["sysName"]], unique = TRUE)
go_db <- load_microbesonline_go(id = 83331, id_column = "sysName")
## The species being downloaded is: Mycobacterium tuberculosis CDC1551 and is being downloaded as 83331.tab.
h37_annot <- load_microbesonline_annotations("H37Rv")
## Found 1 entry.
## Mycobacterium tuberculosis H37RvActinobacteriayes2007-05-08yes10404783332
## The species being downloaded is: Mycobacterium tuberculosis H37Rv
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=83332;export=tab
h37_go <- load_microbesonline_go(id = 83332, id_column = "sysName")
## The species being downloaded is: Mycobacterium tuberculosis H37Rv and is being downloaded as 83332.tab.

That looks pretty reasonable to me, it even has COG groups and all the fun stuff I want.

2.2 Which genome am I using?

Before I start, I should recall which is my current reference genome and see if there is a better alternative since last I looked.

My current genome is strain H37Rv last downloaded in 2022, it is derived from accession NC_000962.3 / assembly GCF_000195955.2. Glancing at the gff file I have, I am guessing that the most appropriate tags to index against are either locus_tag(Rv0003) or gene(recF).

cd preprocessing
start=$(pwd)
for i in $(/bin/ls -d * | grep -v Undeter); do
    cd $i
    cyoa --method prnaseq --species mtuberculosis_h37rv \
         --gff_type gene --gff_tag locus_tag \
         --introns 0 --freebayes 1 \
         --input $(/bin/ls *.gz | tr '\n' ':' | sed 's/:$//g')
    cd $start
done

2.3 The correct Strain is CDC1551

Ok, so let us redo this accordingly.

cd preprocessing
start=$(pwd)
for i in $(/bin/ls -d * | grep -v Undeter); do
    cd $i
    cyoa --method prnaseq --species mycobacterium_tuberculosis_cdc1551 \
         --gff_type gene --gff_tag locus_tag \
         --introns 0 --freebayes 1 \
         --input $(/bin/ls *.gz | tr '\n' ':' | sed 's/:$//g')
    cd $start
done

3 Ortholog search of CDC1551/H37Rv

A few minutes ago I was making a couple of notes to myself, one of which was to explicitly note where PknF is in this strain. Sadly, when I looked into the annotations I downloaded it was unnamed. I was able to make a good guess given that I knew the location in H37Rv and saw a group of genes in CDC1551 in basically the same place in a similar orientation. Later, when the DE finished I was able to prove it by showing that MT1788 (position 1962996) is the most decreased in the Δ strain and most increased in the complement.

With that in mind, I was a little sad to not have the full set of H37Rv annotations available and so am spinning up my favorite ortholog search tool ‘orthofinder’. The following block is where I am going to do that.

I first need to extract the amino acid sequences from H37Rv (I have them in place already for CDC1551).

mkdir orthologs
cd orthologs
cp ~/libraries/genome/mtub*.gb .
cp ~/libraries/genome/myco*.faa .
cyoa --method gb2gff --input *.gb
ls *.faa
cyoa --method orthofinder --input mtuberculosis_h37rv.faa:mycobacterium_tuberculosis_cdc1551.faa

For the curious, that last command generates the following on the computing cluster:

orthofinder -f outputs/50orthofinder/input \
  -o outputs/50orthofinder/output \
  2>>outputs/50orthofinder/orthofinder.stderr 1>>outputs/50orthofinder/orthofinder.stdout
mv outputs/50orthofinder/output/Results_Dec06/* outputs/50orthofinder/output
rmdir outputs/50orthofinder/output/Results_Dec06

It writes the input file for me so that I cannot introduce any annoying typeographical errrors[sic]. It also creates a little job that parses the quite confusing outputs from orthofinder into an (hopefully) easy to read table.

My hope is to shortly be able to append all the H37Rv IDs to my annotation set for CDC1551. We shall see, orthofinder takes ~ 10 minutes / 1000 genes.

3.0.1 Read in orthogroup information

The orthologs produced by orthofinder appear to pick up single-groups for 3343 genes, which seems pretty good, I am assuming the remainder of genes are multi-gene families which will also be nicely identified.

single_orthologs <- as.data.frame(readr::read_tsv("orthologs/outputs/50orthofinder/orthogroups_single_named.tsv"))
## New names:
## • `` -> `...4`
## Warning: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
##   dat <- vroom(...)
##   problems(dat)
## Rows: 3343 Columns: 4
## ── Column specification ───────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (3): Orthogroup, mtuberculosis_h37rv, ...4
## lgl (1): mycobacterium_tuberculosis_cdc1551
## 
## ℹ 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.
rownames(single_orthologs) <- single_orthologs[["Orthogroup"]]
single_orthologs <- single_orthologs[, c(2, 4)]
colnames(single_orthologs) <- c("h37rv", "cdc1551")

## There are a bunch of 1:many mappings and many:many mappings it turns out!
## and I need to reformat the text file containing them, supido orthofinder
## added some random characters in the lists of genes which make it weird to parse.
all_orthogroups <- as.data.frame(readr::read_tsv("orthologs/outputs/50orthofinder/orthogroups_all_named.tsv"))
## New names:
## • `` -> `...2`
## Warning: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
##   dat <- vroom(...)
##   problems(dat)
## Rows: 3551 Columns: 2
## ── Column specification ───────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (2): Orthogroup, ...2
## 
## ℹ 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.

Ok, so I need to do a little work to clean up the (1|many):(1|many) mappings; until then let us just merge the 1:1 mappings into the CDC1551 annotations.

I think I will need to get the NIH IDs from the genbank or gff file before merging to the microbesonline annotations. An important caveat I did not consider before: the ortholog searches were explicitly on CDS/proteins and my general annotations are not.

h37_cds <- load_gff_annotations("orthologs/mtuberculosis_h37rv_all.gff", type = "CDS")
## Returning a df with 30 columns and 3906 rows.
h37_cds_singles <- merge(h37_cds, single_orthologs, by.x = "protein_id",
                         by.y = "h37rv", all.x = TRUE)

cdc_cds <- load_gff_annotations("orthologs/mycobacterium_tuberculosis_cdc1551_cds.gff", type = "CDS")
## Returning a df with 18 columns and 4189 rows.
h37_ncbi_cdc <- merge(h37_cds_singles, cdc_cds, by.x = "cdc1551", by.y = "protein_id")

single_gene_mapping <- h37_ncbi_cdc[, c("locus_tag.x", "locus_tag.y", "gene.x",
                                        "product.x", "gene.y", "product.y")]
colnames(single_gene_mapping) <- c("h37rv_tag", "cdc1551_tag", "h37_gene",
                                   "h37_product", "cdc_gene", "cdc_product")

3.1 Add the single gene maps to the annotations

Oh, the way I did the above, this will almost certainly end up with redundant columns; but since those columns are coming from different sources it will be a good control to ensure that everything worked properly (e.g. if they prove not to be redundant then we know there were shenanigans in my ortholog mapping).

annot <- merge(annot, single_gene_mapping, by.x = "row.names",
               by.y = "cdc1551_tag", all.x = TRUE)
rownames(annot) <- annot[["Row.names"]]
annot[["Row.names"]] <- NULL

4 A slightly random aside, rRNA and 6S

Given the pecularities we observed vis a vis the Pseudomonas reads, there is explicit interest from April to know how well the ribosomal depletion went; so I did a little poking and found that the ribosomal genes are named rrf(5S), rrs(16S), and rrl(23S). When I make a bacterial ribosomal database I usually like to include a few tRNAs and 6S, even though 5S/6S/tRNAs should be size-selected out of the libraries pretty consistently. It turns out the biology of RNAs which interact with σ in Mtb is kind of wild and there is no known 6s, but a somewhat similar RNA named ‘Ms1’.

Anyhow, I made a rRNA database for Mtb and here is a query against it to get a sense of likely rRNA reads in the samples.

cd preprocessing
start=$(pwd)
for i in $(/bin/ls -d * | grep -v Undetermined); do
    cd $i
    cyoa --method hisat --libtype rRNA --species mtuberculosis_h37rv \
         --input $(/bin/ls *-trimmed.fastq.xz | tr '\n' ':' | sed 's/:$//g')
    cd $start
done

5 Append information to the sample sheet

We have a relatively sparse sample sheet to start with, lets add some summary stats from cyoa to it.

There is one important piece of information that Daniel alerted me to which is not included in the gathered metadata (I think): these samples appear to have an extraorindarily large amount of potentially other bacterial sequence in them; and it appears to be dominated by Pseudomonas aeruginosa – I am assuming PA01 and will try mapping the reads against that strain to see what is going on.

Until those mappings are complete, I will continue on as normal, but keep in mind that the following will almost certain need to change.

spec <- make_rnaseq_spec()
gathered <- gather_preprocessing_metadata("sample_sheets/all_samples.xlsx",
                                         species = "mycobacterium_tuberculosis_cdc1551",
                                         specification = spec)
## Skipping for now
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/WT_1/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/WT_2/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/WT_3/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Mutant_pknF_1/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Mutant_pknF_2/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Mutant_pknF_3/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Comp_pknF_1/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Comp_pknF_2/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Warning in dispatch_filename_search(meta, input_file_spec, verbose = verbose, : The input file is NA for:
## preprocessing/Comp_pknF_3/outputs/*salmon_mycobacterium_tuberculosis_cdc1551/quant.sf.
## Writing new metadata to: sample_sheets/all_samples_modified.xlsx
## Deleting the file sample_sheets/all_samples_modified.xlsx before writing the tables.

6 Create an expressionset

expt <- create_expt(gathered[["new_file"]], gene_info = annot, file_column = "hisatcounttable")
## Reading the sample metadata.
## The sample definitions comprises: 9 rows(samples) and 19 columns(metadata fields).
## Matched 4245 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 4245 features and 9 samples.
written <- write_expt(expt, excel = glue("excel/all_samples-v{ver}.xlsx"))
## Writing the first sheet, containing a legend and some summary data.
## 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.
## 86 entries are 0.  We are on a log scale, adding 1 to the data.
## 
## Changed 86 zero count features.
## 
## Naively calculating coefficient of variation/dispersion with respect to condition.
## 
## Finished calculating dispersion estimates.
## 
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## 
## Total:29 s

7 Poke at it

plot_libsize(expt)
## Library sizes of 9 samples, 
## ranging from 3,338,710 to 13,076,335.

plot_nonzero(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.
## A non-zero genes plot of 9 samples.
## These samples have an average 8.867 CPM coverage and 4235 genes observed, ranging from 4227 to
## 4242.

norm <- normalize_expt(expt, transform = "log2", convert = "cpm", norm = "quant", filter = TRUE)
## Removing 91 low-count genes (4154 remaining).
plot_corheat(norm)
## A heatmap of pairwise sample correlations ranging from: 
## 0.924732991192705 to 0.987981556516807.

plot_disheat(norm)
## A heatmap of pairwise sample distances ranging from: 
## 23.2338031782721 to 58.1252671359335.

plot_pca(norm)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by wt, delta, complement
## Shapes are defined by b1, b2, b3.

nb <- normalize_expt(expt, transform = "log2", convert = "cpm", batch = "limma", filter = TRUE)
## Removing 91 low-count genes (4154 remaining).
## If you receive a warning: 'NANs produced', one potential reason is that the data was quantile normalized.
## Setting 2 low elements to zero.
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(nb)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by wt, delta, complement
## Shapes are defined by b1, b2, b3.

ns <- normalize_expt(expt, transform = "log2", convert = "cpm", batch = "svaseq", filter = TRUE)
## Removing 91 low-count genes (4154 remaining).
## Setting 2 low elements to zero.
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(ns)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by wt, delta, complement
## Shapes are defined by b1, b2, b3.

Well, that is not great. I arbitrarily tried a batch in model and sva adjustment, but am not including them without further information.

7.1 Check the rRNA content

The following does not work because I fell into the assumption that these are H37Rv samples again! Doofus.

I guess I could pull the IDs because I matched them against H37Rv; but I also mapped against H37Rv, so I could just use that.

rrna_loci <- c("Rvnr01", "Rvnr02", "Rvnr03")
rrna_expt <- expt[rrna_loci, ]

While I was typing the above incorrectly, the alignments started finishing the query against my Mtb rRNA database. It looks like ~ 3% of the reads map to rRNA.

8 varpart

varpart <- simple_varpart(expt)
## 
## Total:37 s
varpart
## The result of using variancePartition with the model:
## ~ condition + batch

9 Kraken matrix

genus_expt <- create_expt(gathered[["new_file"]],
                          file_column = "krakenmatrix", file_type = "table")
## Reading the sample metadata.
## The sample definitions comprises: 9 rows(samples) and 19 columns(metadata fields).
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/WT_2/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/WT_3/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Mutant_pknF_1/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Mutant_pknF_2/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Mutant_pknF_3/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Comp_pknF_1/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Comp_pknF_2/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in first_rownames != current_rownames: longer object length is not a multiple of shorter object length
## Warning in read_counts_expt(sample_ids, filenames, countdir = countdir, : The file:
## /home/trey/sshfs/scratch/atb/rnaseq/mycobacterium_tuberculosis_2023/preprocessing/Comp_pknF_3/outputs/05kraken_bacteria/kraken_report_matrix.tsv
## has mismatched rownames.
## Warning in create_expt(gathered[["new_file"]], file_column = "krakenmatrix", : There are some NAs in this data,
## the 'handle_nas' parameter may be required.
## Matched 191 annotations and counts.
## Bringing together the count matrix and gene information.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 191 features and 9 samples.
genus_norm <- normalize_expt(genus_expt, convert = "cpm")
plot_disheat(genus_norm)
## A heatmap of pairwise sample distances ranging from: 
## 4945.06863345337 to 102810.646015848.

genus_normv2 <- normalize_expt(genus_expt, convert = "cpm", transform = "log2")
plot_pca(genus_normv2)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by wt, delta, complement
## Shapes are defined by b1, b2, b3.

plot_libsize(genus_expt)
## Library sizes of 9 samples, 
## ranging from 371,301 to 2,637,312.

head(exprs(genus_expt))
##                  WT_1 WT_2 WT_3 Mutant_pknF_1 Mutant_pknF_2 Mutant_pknF_3 Comp_pknF_1 Comp_pknF_2 Comp_pknF_3
## Acetobacter        96   29   66           116            81            53          27         146         143
## Achromobacter      26   20   15            34            28            21           6          49          59
## Acidiferrobacter   26    8   12            18            21            10           2          23          31
## Acidihalobacter    14    5   11            23            38            11           4          38          40
## Acinetobacter     819  314  448           770           691           477         147        1130         962
## Actinobacillus     26   20   26            36            36            10           4          28          32
exprs(genus_expt)["Pseudomonas", ]
##          WT_1          WT_2          WT_3 Mutant_pknF_1 Mutant_pknF_2 Mutant_pknF_3   Comp_pknF_1   Comp_pknF_2 
##       1509718        546307       1020882       1635517       1502338        902653        341293       2477879 
##   Comp_pknF_3 
##       2388934

10 Differential Expression

I am going to assume for the moment that we can learn interesting things from the data, but that it will require more intervention than usual for a bacterial dataset.

keepers <- list(
  "delta_wt" = c("delta", "wt"),
  "comp_wt" = c("complement", "wt"),
  "delta_comp" = c("delta", "complement"))
de <- all_pairwise(expt, keepers = keepers, filter = TRUE, model_batch = "svaseq")
## 
##         wt      delta complement 
##          3          3          3
## Removing 0 low-count genes (4154 remaining).
## Setting 2 low elements to zero.
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.

tables <- combine_de_tables(
  de, keepers = keepers, excel = glue("excel/de_tables-v{ver}.xlsx"))
## Checking limma for name delta_wt:wt_vs_delta
## Checking deseq for name delta_wt:wt_vs_delta
## Checking edger for name delta_wt:wt_vs_delta
## Checking ebseq for name delta_wt:wt_vs_delta
## Checking noiseq for name delta_wt:wt_vs_delta
## Checking basic for name delta_wt:wt_vs_delta
## Checking limma for name comp_wt:wt_vs_complement
## Checking deseq for name comp_wt:wt_vs_complement
## Checking edger for name comp_wt:wt_vs_complement
## Checking ebseq for name comp_wt:wt_vs_complement
## Checking noiseq for name comp_wt:wt_vs_complement
## Checking basic for name comp_wt:wt_vs_complement
## Checking limma for name delta_comp:complement_vs_delta
## Checking deseq for name delta_comp:complement_vs_delta
## Checking edger for name delta_comp:complement_vs_delta
## Checking ebseq for name delta_comp:delta_vs_complement
## Checking noiseq for name delta_comp:complement_vs_delta
## Checking basic for name delta_comp:complement_vs_delta
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: ebseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: ebseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
sig <- extract_significant_genes(
  tables, according_to = "deseq", excel = glue("excel/de_sig-v{ver}.xlsx"))

10.1 Also provide a less stringent version

less_stringent <- extract_significant_genes(
  tables, according_to = "deseq", lfc = 0.6, p = 1,
  excel = glue("excel/de_sig_0.6lfc_1.0pval-v{ver}.xlsx"))

10.1.1 Test batch-in-model

Given the PCA above, it seems at least possible that including batch in model might provide more reliable results than sva. So, the following block does that. Spoiler alert: I don’t think it helped.

de_batch <- all_pairwise(expt, keepers = keepers, filter = TRUE, model_batch = TRUE)
## 
##         wt      delta complement 
##          3          3          3 
## 
## b1 b2 b3 
##  3  3  3
de_batch
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: batch in model/limma.
## The primary analysis performed 15 comparisons.
tables_batch <- combine_de_tables(de_batch, keepers = keepers,
                                  excel = glue("excel/de_tables_batch-v{ver}.xlsx"))
## Checking limma for name delta_wt:wt_vs_delta
## Checking deseq for name delta_wt:wt_vs_delta
## Checking edger for name delta_wt:wt_vs_delta
## Checking ebseq for name delta_wt:wt_vs_delta
## Checking noiseq for name delta_wt:wt_vs_delta
## Checking basic for name delta_wt:wt_vs_delta
## Checking limma for name comp_wt:wt_vs_complement
## Checking deseq for name comp_wt:wt_vs_complement
## Checking edger for name comp_wt:wt_vs_complement
## Checking ebseq for name comp_wt:wt_vs_complement
## Checking noiseq for name comp_wt:wt_vs_complement
## Checking basic for name comp_wt:wt_vs_complement
## Checking limma for name delta_comp:complement_vs_delta
## Checking deseq for name delta_comp:complement_vs_delta
## Checking edger for name delta_comp:complement_vs_delta
## Checking ebseq for name delta_comp:delta_vs_complement
## Checking noiseq for name delta_comp:complement_vs_delta
## Checking basic for name delta_comp:complement_vs_delta
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: ebseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: ebseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
## About to start combine_mapped_table()
## Inverting column: basic_logfc.
## Inverting column: deseq_logfc.
## Inverting column: edger_logfc.
## Inverting column: limma_logfc.
## Inverting column: noiseq_logfc.
## Finished combine_mapped_table()
tables_batch
## A set of combined differential expression results.

##                          table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1         wt_vs_delta-inverted          31             1          16             3           2             1
## 2    wt_vs_complement-inverted          17             7          14             6           2             1
## 3 complement_vs_delta-inverted          12             9          11             8           1             1

sig_batch <- extract_significant_genes(tables_batch, according_to = "deseq",
                                       excel = glue("excel/de_sig_batch-v{ver}.xlsx"))
sig_batch
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## delta_wt         31          1
## comp_wt          17          7
## delta_comp       12          9

10.2 The intersection of Δ/WT and Δ/comp

library(UpSetR)
first_up <- sig[["deseq"]][["ups"]][["delta_wt"]]
second_up <- sig[["deseq"]][["ups"]][["delta_comp"]]

first_down <- sig[["deseq"]][["downs"]][["delta_wt"]]
second_down <- sig[["deseq"]][["downs"]][["delta_comp"]]

comparison <- list(
  "d_w_up" = rownames(first_up),
  "d_c_up" = rownames(second_up),
  "d_w_down" = rownames(first_down),
  "d_c_down" = rownames(second_down))
query <- UpSetR::fromList(comparison)
sets <- UpSetR::upset(query)
sets

## So, there are 2 shared down and 12 up.  Also 1 weirdo (which given
## its proximity to the operon containing PknF is likely interesting)

overlap_ids <- overlap_groups(comparison)
interesting_up <- overlap_geneids(overlap_ids, "d_w_up:d_c_up")
interesting_up
##  d_w_up3  d_w_up6 d_w_up18 d_w_up20 d_w_up29 d_w_up30 d_w_up37 d_w_up45 d_w_up57 d_w_up71 d_w_up90 d_w_up95 
## "MT3214" "MT0995" "MT2020" "MT0423" "MT1255" "MT0424" "MT2579" "MT2574" "MT3712" "MT2576" "MT1256" "MT0595"
interesting_down <- overlap_geneids(overlap_ids, "d_w_down:d_c_down")
interesting_down
## d_c_up25 d_c_up26 
## "MT1702" "MT0995"
weirdo <- overlap_geneids(overlap_ids, "d_w_up:d_c_down")
weirdo
##  d_w_up2 
## "MT1790"
overlapping_meta <- annot[c(interesting_up, interesting_down, weirdo), ]
written <- write_xlsx(overlapping_meta, excel = "excel/overlapping_stringent_genes.xlsx")
## Deleting the file excel/overlapping_stringent_genes.xlsx before writing the tables.

10.3 Repeat the intersection of Δ/WT and Δ/comp with the less significant data

first_up <- less_stringent[["deseq"]][["ups"]][["delta_wt"]]
second_up <- less_stringent[["deseq"]][["ups"]][["delta_comp"]]

first_down <- less_stringent[["deseq"]][["downs"]][["delta_wt"]]
second_down <- less_stringent[["deseq"]][["downs"]][["delta_comp"]]

comparison <- list(
  "d_w_up" = rownames(first_up),
  "d_c_up" = rownames(second_up),
  "d_w_down" = rownames(first_down),
  "d_c_down" = rownames(second_down))
query <- UpSetR::fromList(comparison)
sets <- UpSetR::upset(query)
sets

## So, there are 2 shared down and 12 up.  Also 1 weirdo (which given
## its proximity to the operon containing PknF is likely interesting)

overlap_ids <- overlap_groups(comparison)
interesting_up <- overlap_geneids(overlap_ids, "d_w_up:d_c_up")
interesting_up
##     d_w_up1     d_w_up3     d_w_up6     d_w_up7     d_w_up9    d_w_up10    d_w_up11    d_w_up12    d_w_up14 
##    "MT1789"    "MT3214"    "MT0995"    "MT1002"    "MT2707"    "MT2115"    "MT3249"    "MT1001"    "MT0996" 
##    d_w_up16    d_w_up17    d_w_up19    d_w_up21    d_w_up23    d_w_up24    d_w_up25    d_w_up28    d_w_up29 
##    "MT1003"    "MT2052"    "MT2020"    "MT0423"    "MT0705"  "MT1003.1"    "MT2216"    "MT2215"    "MT0368" 
##    d_w_up30    d_w_up31    d_w_up32    d_w_up33    d_w_up36    d_w_up37    d_w_up39    d_w_up41    d_w_up42 
##    "MT1255"    "MT0424"    "MT1511"    "MT0265"    "MT0706" "MT3573.12"    "MT2579"    "MT0845"    "MT0296" 
##    d_w_up44    d_w_up45    d_w_up46    d_w_up47    d_w_up48    d_w_up49    d_w_up50    d_w_up51    d_w_up52 
##    "MT1000"    "MT1200"    "MT1400"    "MT2703"    "MT3250"    "MT2574"    "MT2021"    "MT1512"    "MT2053" 
##    d_w_up53    d_w_up54    d_w_up58    d_w_up59    d_w_up60    d_w_up61    d_w_up62    d_w_up65    d_w_up66 
##    "MT2704"    "MT2705"    "MT3907"    "MT2578"    "MT2783"    "MT3217"    "MT3712"    "MT2815"    "MT3342" 
##    d_w_up67    d_w_up70    d_w_up72    d_w_up76    d_w_up77    d_w_up81    d_w_up82    d_w_up83    d_w_up84 
##    "MT0397"  "MT0706.1"    "MT0367"    "MT2576"    "MT3263"    "MT2050"    "MT0787"    "MT2600"    "MT2577" 
##    d_w_up85    d_w_up86    d_w_up87    d_w_up90    d_w_up92    d_w_up95    d_w_up96    d_w_up97    d_w_up98 
##    "MT2816"    "MT3632"    "MT3216"    "MT3644"    "MT0297" "MT3573.11"    "MT1256"    "MT0366"    "MT2573" 
##   d_w_up101   d_w_up102   d_w_up105   d_w_up107   d_w_up108   d_w_up110   d_w_up115   d_w_up125   d_w_up131 
##    "MT0595"    "MT2306"    "MT1011"    "MT0596"    "MT1636"    "MT1637"    "MT0425"    "MT0846"    "MT1199" 
##   d_w_up133   d_w_up136   d_w_up139   d_w_up143   d_w_up150   d_w_up151   d_w_up152   d_w_up159   d_w_up172 
##    "MT1510"    "MT3646"    "MT0115"    "MT2702"    "MT1641"    "MT3165"    "MT2904"    "MT1540"    "MT3326" 
##   d_w_up173   d_w_up174   d_w_up175   d_w_up183   d_w_up186   d_w_up191   d_w_up200   d_w_up207   d_w_up208 
##    "MT2090"    "MT0295"    "MT3985"    "MT2091"    "MT3645"    "MT1102"    "MT0365"    "MT2571"    "MT1639" 
##   d_w_up209   d_w_up212   d_w_up217   d_w_up218   d_w_up224   d_w_up231   d_w_up236   d_w_up264   d_w_up265 
##    "MT2049"    "MT2005"    "MT3219"    "MT3220"    "MT2572"    "MT2015"    "MT2701"  "MT3712.1"    "MT1508" 
##   d_w_up267   d_w_up269   d_w_up270   d_w_up274   d_w_up277   d_w_up286   d_w_up287   d_w_up297   d_w_up303 
##    "MT3983"    "MT3984"    "MT1638"    "MT2061"    "MT2575"    "MT3212"    "MT2022"    "MT1774"    "MT0305" 
##   d_w_up311   d_w_up313   d_w_up317   d_w_up319   d_w_up340   d_w_up343   d_w_up344   d_w_up347   d_w_up348 
##    "MT2698"    "MT2383"    "MT1126"    "MT1012"    "MT1779"    "MT1010"    "MT0292"    "MT1198"    "MT2570" 
##   d_w_up398   d_w_up400   d_w_up401   d_w_up425   d_w_up438   d_w_up439   d_w_up441   d_w_up443   d_w_up445 
##    "MT2305"    "MT3002"    "MT2059"    "MT2660"    "MT0298"    "MT1257"    "MT2087"    "MT0070"    "MT1479" 
##   d_w_up451 
##    "MT2303"
interesting_down <- overlap_geneids(overlap_ids, "d_w_down:d_c_down")
interesting_down
##   d_c_up105   d_c_up106   d_c_up107   d_c_up108   d_c_up109   d_c_up110   d_c_up111   d_c_up112   d_c_up114 
##  "MT3427.1"    "MT3644"    "MT0598"    "MT2954"    "MT2600"    "MT0368"  "MT0706.1"    "MT2705"    "MT0425" 
##   d_c_up118   d_c_up119   d_c_up120   d_c_up123   d_c_up124   d_c_up127   d_c_up130   d_c_up131   d_c_up134 
##    "MT0295"    "MT2305"    "MT1225"    "MT3249"  "MT3194.1"    "MT0996"    "MT2815"    "MT3263"    "MT1639" 
##   d_c_up135   d_c_up136   d_c_up139   d_c_up140   d_c_up142   d_c_up144   d_c_up145   d_c_up147   d_c_up150 
##    "MT2116"    "MT3342"    "MT0896"    "MT3218"    "MT1126"    "MT1557"    "MT3165"    "MT2215"    "MT3632" 
##   d_c_up153   d_c_up155   d_c_up158   d_c_up159   d_c_up163   d_c_up167   d_c_up172   d_c_up174   d_c_up181 
##    "MT0736"    "MT0846"    "MT0265"    "MT2053"    "MT0730"    "MT0599"    "MT1017"    "MT1000"    "MT1779" 
##   d_c_up182   d_c_up183   d_c_up184   d_c_up192   d_c_up193   d_c_up201   d_c_up206   d_c_up208   d_c_up209 
##    "MT0746"    "MT1605"  "MT1003.1"    "MT0938"    "MT2660"    "MT1774"    "MT1510"    "MT2878"    "MT2216" 
##   d_c_up212   d_c_up214   d_c_up215   d_c_up225   d_c_up226   d_c_up227   d_c_up230   d_w_down2   d_w_down3 
##    "MT2572"    "MT2889"    "MT0397"    "MT2606"    "MT0787"    "MT2383"    "MT1010"    "MT1152"    "MT3745" 
##   d_w_down5  d_w_down11  d_w_down13  d_w_down15  d_w_down16  d_w_down23  d_w_down24  d_w_down25  d_w_down30 
##  "MT3718.1"    "MT0174"    "MT3413"  "MT1169.1"    "MT1170"    "MT3905"    "MT0992"    "MT1067"    "MT1184" 
##  d_w_down31  d_w_down37  d_w_down45  d_w_down47  d_w_down53  d_w_down55  d_w_down56  d_w_down60  d_w_down67 
##    "MT1757"    "MT0117"    "MT0273"    "MT2349"    "MT2246"    "MT3585"    "MT1798"    "MT3844"    "MT2952" 
##  d_w_down68  d_w_down70  d_w_down76  d_w_down78  d_w_down90  d_w_down92  d_w_down95  d_w_down99 d_w_down100 
##    "MT2396"  "MT0204.1"    "MT3133"    "MT0084"    "MT0918"    "MT2730"    "MT2106"    "MT3402"    "MT2148" 
## d_w_down102 d_w_down111 
##    "MT2808"    "MT2393"
weirdo <- overlap_geneids(overlap_ids, "d_w_up:d_c_down")
weirdo
##    d_w_up2  d_w_up146  d_w_up187  d_w_up281  d_w_up328  d_w_up332  d_w_up396  d_w_up405  d_w_up433  d_w_up452 
##   "MT1790"   "MT0850"   "MT2527"   "MT2069"   "MT3211"   "MT0342"   "MT2075" "MT1707.1"   "MT3283"   "MT2068"
overlapping <- as.character(c(interesting_up, interesting_down, weirdo))

overlapping_meta <- annot[c(interesting_up, interesting_down, weirdo), ]
written <- write_xlsx(overlapping_meta, excel = "excel/overlapping_less_stringent_genes.xlsx")
## Deleting the file excel/overlapping_less_stringent_genes.xlsx before writing the tables.

11 Ontology enrichment

Given the relative sparsity of the annotations for CDC1551, I might either go back to my H37Rv mapping data (which was pretty decent), or use the orthologs and their annotations; but since I already have the data in its current form loaded, let us just try it and see.

11.1 Volker’s explicit query first

There are only 15 genes in the set of interesting intersections; so I am going to group them together.

In my annotation block above I downloaded the H37Rv and CDC1551 annotations/GO categories. There appears to be a bug in the GO loader, it needed the actual ID number instead of a unique string like the annotations; happily the annotation load prints out the ID number so I did not have to think very hard.

11.1.1 Length and COG databases

I forgot for a couple weeks to perform the same overrepresentation analyses using the COG function assignments. Let us create that association table here and add the goseq searches below.

annot[["length"]] <- abs(annot[["start"]] - annot[["stop"]])
length_db <- as.data.frame(annot[, c("name", "length")])
colnames(length_db) <- c("ID", "length")

start_cog_df <- annot[, c("desc", "COG", "COGFun", "COGDesc", "TIGRFam", "TIGRRoles")]
start_cog_df[["ID"]] <- rownames(start_cog_df)
cog_df <- start_cog_df[, c("ID", "COGFun")]
colnames(cog_df) <- c("ID", "GO")

11.2 The ontology searches

query_genes <- unique(c(interesting_up, interesting_down, weirdo))

goseq_query <- simple_goseq(query_genes, go_db = go_db,
                            length_db = length_db, min_xref = 4)
## Found 113 go_db genes and 147 length_db genes out of 187.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_query
## A set of ontologies produced by goseq using 187
## with significance cutoff 0.1.
## There are 25 MF hits, 19, BP hits, and 2 CC hits.
## Category mfp_plot_over is the most populated with 12 hits.

cog_query <- simple_goseq(query_genes, go_db = cog_df,
                          expand_categories = FALSE,
                          length_db = length_db, min_xref = 3)
## Found 187 go_db genes and 147 length_db genes out of 187.

11.2.1 Same thing, less stringent

goseq_query <- simple_goseq(unique(overlapping), go_db = go_db,
                            length_db = length_db, min_xref = 4)
goseq_query
written <- write_goseq_data(goseq_query, excel = "excel/goseq_less_stringent_results.xlsx")

topgo_query <- simple_topgo(unique(overlapping), excel = "excel/topgo_less_stringent_results.xlsx"))
## Error: <text>:6:100: unexpected ')'
## 5: 
## 6: topgo_query <- simple_topgo(unique(overlapping), excel = "excel/topgo_less_stringent_results.xlsx"))
##                                                                                                       ^

Given that there are only a few genes in the above query, let us also do the three primary contrasts separately as I think they will prove more interesting.

goseq_up_delta_wt <- simple_goseq(sig[["deseq"]][["ups"]][["delta_wt"]], go_db = go_db,
                                  length_db = length_db)
## Found 67 go_db genes and 83 length_db genes out of 108.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_up_delta_wt
## A set of ontologies produced by goseq using 108
## with significance cutoff 0.1.
## There are 27 MF hits, 12, BP hits, and 2 CC hits.
## Category mfp_plot_over is the most populated with 11 hits.

goseq_down_delta_wt <- simple_goseq(sig[["deseq"]][["downs"]][["delta_wt"]], go_db = go_db,
                                    length_db = length_db)
## Found 3 go_db genes and 17 length_db genes out of 17.
goseq_down_delta_wt
## NULL
goseq_up_comp_wt <- simple_goseq(sig[["deseq"]][["ups"]][["comp_wt"]], go_db = go_db,
                                  length_db = length_db, min_xref = 20)
## Found 27 go_db genes and 51 length_db genes out of 54.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_up_comp_wt
## A set of ontologies produced by goseq using 54
## with significance cutoff 0.1.
## There are 20 MF hits, 11, BP hits, and 0 CC hits.
## Category mfp_plot_over is the most populated with 8 hits.

goseq_down_comp_wt <- simple_goseq(sig[["deseq"]][["downs"]][["comp_wt"]], go_db = go_db,
                                    length_db = length_db, min_xref = 5)
## Found 6 go_db genes and 24 length_db genes out of 25.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_down_comp_wt
## A set of ontologies produced by goseq using 25
## with significance cutoff 0.1.
## There are 4 MF hits, 3, BP hits, and 0 CC hits.
## Category mfp_plot_over is the most populated with 3 hits.

goseq_up_delta_comp <- simple_goseq(sig[["deseq"]][["ups"]][["delta_comp"]], go_db = go_db,
                                    length_db = length_db, min_xref = 10)
## Found 20 go_db genes and 32 length_db genes out of 36.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_up_delta_comp
## A set of ontologies produced by goseq using 36
## with significance cutoff 0.1.
## There are 8 MF hits, 3, BP hits, and 1 CC hits.
## Category mfp_plot_over is the most populated with 7 hits.

goseq_down_delta_comp <- simple_goseq(sig[["deseq"]][["downs"]][["delta_comp"]], go_db = go_db,
                                    length_db = length_db, min_xref = 5)
## Found 7 go_db genes and 31 length_db genes out of 32.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
goseq_down_delta_comp
## A set of ontologies produced by goseq using 32
## with significance cutoff 0.1.
## There are 4 MF hits, 2, BP hits, and 1 CC hits.
## Category mfp_plot_over is the most populated with 4 hits.

12 Circos

I think it would be nice to have the wt mean expression values as a baseline

means <- mean_by_factor(norm)[["medians"]]
## The factor wt has 3 rows.
## The factor delta has 3 rows.
## The factor complement has 3 rows.

12.1 Collect the STPKs

stpk_operons <- c("pknA", "pknB", ## ~15k, perhaps ending a 7 gene operon (fhaA, fhaB, pstP, rodA, rbpA, pknA, pknB)
                 ## No pknC
                 "pknD", ## ~ 1038500, perhaps 2 gene operon with pstS2
                 "pknE", ## ~ 2000000, perhaps with vapB34, vapC34, Rv1742, pknE
                 "pknF", ## ~ 2000000, close to E, pknF, Rv1747, Rv1748
                 "pknG", ## ~ 2000000, Rv0412c, hlnH, pknG
                 "pknH", ## ~ 1415000, maybe 8 genes, Rv1273c, Rv1272c, Rv1271c, lprA, Rv1269c, Rv1268c, embR, pknH
                 "pknI", ## ~ 3222000, ffh, Rv2915c, pknI, Rv2913c, Rv2912c
                 "pknJ", ## ~ 2345000, Rv2082, Rv2083, Rv2084, Rv2085, Rv2086, Rv2087, pknJ
                 "pknK", ## ~ 3442500, pknK, Rv3079c
                 "pknL",
                 "lppH" ## when searching for pknM, lpphH, Rv3577, arsB2 4015000
                 )
mapped_stpk <- single_gene_mapping[["h37_gene"]] %in% stpk_operons
mapped_ids <- single_gene_mapping[mapped_stpk, ]
mapped_ids
##      h37rv_tag cdc1551_tag h37_gene                                        h37_product cdc_gene
## 14     Rv0014c      MT0017     pknB               serine/threonine-protein kinase PknB     <NA>
## 15     Rv0015c      MT0018     pknA               serine/threonine-protein kinase PknA     <NA>
## 346    Rv0410c      MT0423     pknG               serine/threonine-protein kinase PknG     <NA>
## 778    Rv0931c      MT0958     pknD               serine/threonine-protein kinase PknD     <NA>
## 1051   Rv1266c      MT1304     pknH               serine/threonine-protein kinase PknH     <NA>
## 1462    Rv1743      MT1785     pknE               serine/threonine-protein kinase PknE     <NA>
## 1465    Rv1746      MT1788     pknF               serine/threonine-protein kinase PknF     <NA>
## 1755    Rv2088      MT2149     pknJ transmembrane serine/threonine-protein kinase PknJ     <NA>
## 1832    Rv2176      MT2232     pknL               serine/threonine-protein kinase PknL     <NA>
## 2474   Rv2914c      MT2982     pknI               serine/threonine-protein kinase PknI     <NA>
## 2614   Rv3080c      MT3165     pknK               serine/threonine-protein kinase PknK     <NA>
## 3040    Rv3576      MT3681     lppH                                   lipoprotein LppH     <NA>
##                                                 cdc_product
## 14                          serine/threonine protein kinase
## 15                          serine/threonine protein kinase
## 346                         serine/threonine protein kinase
## 778                         serine/threonine protein kinase
## 1051                        serine/threonine protein kinase
## 1462                        serine/threonine protein kinase
## 1465                        serine/threonine protein kinase
## 1755                        serine/threonine protein kinase
## 1832                        serine/threonine protein kinase
## 2474                        serine/threonine protein kinase
## 2614 serine/threonine protein kinase / MalT-related protein
## 3040                                   hypothetical protein
mapped_ids[["cdc1551_tag"]]
##  [1] "MT0017" "MT0018" "MT0423" "MT0958" "MT1304" "MT1785" "MT1788" "MT2149" "MT2232" "MT2982" "MT3165" "MT3681"
## Oh no shit the reason I couldn't find them before was the difference between pknB and PknB, damnit.
## So that is annoying I likely did not need to do the silly ortholog map at all.

Let us add a column to the annotations noting the STPKs and potentially include them in the circos plot.

The current map is in order from outer->inner

    • strand genes colored by COGFun
    • strand genes
  • WT gene expression on log scale, color scale chosen automatically as heatmap
  • Δ/WT comparison on log scale, color scale chosen automatically as heatmap
  • comp/WT comparison, Ibid.
  • Δ/comp comparison, Ibid.
  • ideally, tiles showing the location of the 11 STPKs and 1 rando which might also be a STPK.
annot[["chromosome"]] <- "AE000516"
annot[["stpk"]] <- "NULL"
annot[mapped_ids[["cdc1551_tag"]], "stpk"] <- "stpk"
stpk_rows <- annot[mapped_ids[["cdc1551_tag"]], ]

delta_wt_df <- tables[["data"]][["delta_wt"]][, c("deseq_logfc", "deseq_adjp")]
comp_wt_df <- tables[["data"]][["comp_wt"]][, c("deseq_logfc", "deseq_adjp")]
delta_comp_df <- tables[["data"]][["delta_comp"]][, c("deseq_logfc", "deseq_adjp")]

pknf_cfg <- circos_prefix(annot, name="pknf", cog_column = "COGFun",
                          start_column = "start", stop_column = "stop",
                          strand_column = "strand", chr_column = "chromosome")
## 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/pknf.conf with a reasonable first approximation config file.
## Wrote karyotype to circos/conf/ideograms/pknf.conf
## This should match the ideogram= line in pknf.conf
## Wrote ticks to circos/conf/ticks_pknf.conf
pknf_kary <- circos_karyotype(
  pknf_cfg, fasta = "~/libraries/genome/mycobacterium_tuberculosis_cdc1551.fasta")
## Wrote karyotype to circos/conf/karyotypes/pknf.conf
## This should match the karyotype= line in pknf.conf
plus_minus <- circos_plus_minus(pknf_cfg, width = 0.06, thickness = 40)
## Writing data file: circos/data/pknf_plus_go.txt with the + strand GO data.
## Writing data file: circos/data/pknf_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.
wt_exprs_heat <- circos_heatmap(pknf_cfg, means, colname = "wt", basename = "mean_wt",
                             outer = plus_minus)
## Assuming the input is a dataframe.
## Writing data file: circos/data/pknf_mean_wtwt_heatmap.txt with the mean_wtwt column.
## Returning the inner width: 0.78.  Use it as the outer for the next ring.
delta_wt_hist <- circos_heatmap(pknf_cfg, delta_wt_df, colname = "deseq_logfc",
                             basename = "delta_wt", outer = wt_exprs_heat)
## Assuming the input is a dataframe.
## Writing data file: circos/data/pknf_delta_wtdeseq_logfc_heatmap.txt with the delta_wtdeseq_logfc column.
## Returning the inner width: 0.68.  Use it as the outer for the next ring.
comp_wt_hist <- circos_heatmap(pknf_cfg, comp_wt_df, colname = "deseq_logfc",
                            basename = "comp_wt", outer = delta_wt_hist)
## Assuming the input is a dataframe.
## Writing data file: circos/data/pknf_comp_wtdeseq_logfc_heatmap.txt with the comp_wtdeseq_logfc column.
## Returning the inner width: 0.58.  Use it as the outer for the next ring.
delta_comp_hist <- circos_heatmap(pknf_cfg, delta_comp_df, colname = "deseq_logfc",
                                  basename = "delta_comp", outer = comp_wt_hist)
## Assuming the input is a dataframe.
## Writing data file: circos/data/pknf_delta_compdeseq_logfc_heatmap.txt with the delta_compdeseq_logfc column.
## Returning the inner width: 0.48.  Use it as the outer for the next ring.
tile_colors <- "0000AA"
names(tile_colors) <- c("stpk")
stpk_tiles <- circos_tile(pknf_cfg, stpk_rows, colname = "stpk",
                          colors = tile_colors, width = 0.125,
                          padding = 0, thickness = 125, margin = 0.00,
                          basename = "stpk", outer = delta_comp_hist)
## Writing data file: circos/data/pknfstpk_tile.txt with the stpkstpk column.
## Returning the inner width: 0.355.  Use it as the outer for the next ring.
finish <- circos_suffix(pknf_cfg)
made <- circos_make(pknf_cfg, target = "pknf")

One of the primary reasons I usually do histograms instead of heatmaps: I do not really understand how to lay out the color range so that it is consistent across different ranges of logFC values (I suppose I could just normalize them to -1<=x<=1?

The following is pulled from a Pseudomonas tiling of specific genes of interest; I have a feeling that the various STPKs may want to be added in a similar fashion

other <- c("gene1652095", "gene1652097", "gene1652099", "gene1652101",
           "gene1652103", "gene1652105", "gene1652107", "gene1652109",
           "gene1652111", "gene1652113", "gene1652115", "gene1652117",
           "gene1652119", "gene1652121", "gene1652123", "gene1652125",
           "gene1652127", "gene1652129", "gene1652131", "gene1652133",
           "gene1652135", "gene1652137", "gene1652139", "gene1652141",
           "gene1652143", "gene1652145", "gene1652147", "gene1652149",
           "gene1652151", "gene1652153", "gene1652155", "gene1652157",
           "gene1652159", "gene1652161", "gene1652163", "gene1652165")
## also BLUE
pel <- c("gene1654787", "gene1654789", "gene1654793",
         "gene1654795", "gene1654797", "gene1654799")
extra[down_orn, "flag"] <- "down_orn"
extra[up_orn, "flag"] <- "up_orn"
extra[effectors, "flag"] <- "effectors"
extra[other, "flag"] <- "other"
extra[pel, "flag"] <- "pel"
keep_idx <- extra[["flag"]] != ""
extra <- extra[keep_idx, ]
summary(as.factor(extra$flag))
LS0tCnRpdGxlOiAiU2VxdWVuY2luZyAzIE15Y29iYWN0ZXJpdW0gVHViZXJjdWxvc2lzIHN0cmFpbnMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQpib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgbWF4LXdpZHRoOiAxNjAwcHg7Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KGhwZ2xkYXRhKQpsaWJyYXJ5KHJldGljdWxhdGUpCmxpYnJhcnkoZ2x1ZSkKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KAogIHByb2dyZXNzID0gVFJVRSwgdmVyYm9zZSA9IFRSVUUsIHdpZHRoID0gOTAsIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXJyb3IgPSBUUlVFLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnJldGluYSA9IDIsCiAgZmlnLnBvcyA9ICJ0IiwgZmlnLmFsaWduID0gImNlbnRlciIsIGRwaSA9IGlmIChrbml0cjo6aXNfbGF0ZXhfb3V0cHV0KCkpIDcyIGVsc2UgMzAwLAogIG91dC53aWR0aCA9ICIxMDAlIiwgZGV2ID0gInBuZyIsCiAgZGV2LmFyZ3MgPSBsaXN0KHBuZyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzID0gNCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSkKdmVyIDwtICIyMDIzMTEiCnByZXZpb3VzX2ZpbGUgPC0gIiIKdmVyIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCAiJVklbSVkIikKCiMjdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKQpybWRfZmlsZSA8LSAiaW5kZXguUm1kIgpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIHByb2plY3Qgc2Vla3MgdG8gdW5kZXJzdGFuZCB0aGUgZWZmZWN0cyBvZiBkZWxldGluZy9jb21wbGVtZW50aW5nCnBrbkYgaW4gTXRiLiBJIGNhbm5vdCBob25lc3RseSBzYXkgSSBrbm93IGFueXRoaW5nIGFib3V0IHRoZSBiaW9sb2d5Cmludm9sdmVkIGV4Y2VwdCB0aGUgYml0cyBmcm9tIHRoZSByZXZpZXcgVm9sa2VyIGtpbmRseSBzZW50IG1lLgoKcGtuRiBpcyBvbmUgb2YgdGhlIHN1cnByaXNpbmdseSBsYXJnZSBudW1iZXIgb2Ygc2VyaW5lIHRocmVvbmluZQpwcm90ZWluIGtpbmFzZXMgaW4gTXRiLiAgTW9zdCBiYWN0ZXJpYSBoYXZlIG9ubHkgYSBjb3VwbGUvZmV3IG9mCnRoZXNlLCBidXQgTXRiIGhhcyAxMSwgYW5kIHVzZXMgdGhlbSB3aXRoIHNpbWlsYXIgZnJlcXVlbmN5IHRvIHRoZSB0d28KY29tcG9uZW50IHN5c3RlbXMgaW4gb3JkZXIgdG8gcmVzcG9uZCB0byBpdHMgY2hhbmdpbmcgZW52aXJvbm1lbnQKZHVyaW5nIGluZmVjdGlvbiAoSSBhc3N1bWUsIEkgaGF2ZSBub3QgZ290dGVuIHRoYXQgZmFyIGluIHRoZSByZXZpZXcKeWV0KS4gIEluIHByZXZpb3VzIGV4cGVyaW1lbnRzIHBlcmZvcm1lZCBieSBwZW9wbGUgaW4gVm9sa2VyJ3MgbGFiLAphIGRlbGV0aW9uIG9mIHRoaXMgcGFydGljdWxhciBTVFBLIGNhdXNlcyBhIG11Y2ggbW9yZSB2aXJ1bGVudApwaGVub3R5cGUgZHVyaW5nIG1vdXNlIGluZmVjdGlvbi4KCiMgUHJlcHJvY2Vzc2luZwoKSSB3cm90ZSBhIHF1aWNrIHNhbXBsZSBzaGVldCBmb3IgdGhlc2UgOSBzYW1wbGVzIGFuZCB3aWxsIHVzZSBteSBjeW9hCnRveSB0byBwZXJmb3JtIHRoZSB2YXJpb3VzIHRhc2tzIHRvIHByb2Nlc3MgdGhlIGRhdGEuCgojIyBXaGF0IGFubm90YXRpb25zIGRvIEkgaGF2ZT8KCkkgYW0gYXNzdW1pbmcgdGhlIG1vc3QgYXBwcm9wcmlhdGUgYW5ub3RhdGlvbnMgY29tZSBmcm9tCm1pY3JvYmVzb25saW5lPyAgTGV0IHVzIGNoZWNrIHJlYWwgcXVpY2suICBJIHNob3VsZCBwcm9iYWJseSBnbyBiYWNrCnRocm91Z2ggbXkgb2xkIGxvZ3MgdG8gYW5zd2VyIHRoZXNlIHF1ZXN0aW9ucy4KCmBgYHtyfQphbm5vdCA8LSBsb2FkX21pY3JvYmVzb25saW5lX2Fubm90YXRpb25zKCJDREMxNTUxIikKYW5ub3QgPC0gYXMuZGF0YS5mcmFtZShhbm5vdCkKcm93bmFtZXMoYW5ub3QpIDwtIG1ha2UubmFtZXMoYW5ub3RbWyJzeXNOYW1lIl1dLCB1bmlxdWUgPSBUUlVFKQpnb19kYiA8LSBsb2FkX21pY3JvYmVzb25saW5lX2dvKGlkID0gODMzMzEsIGlkX2NvbHVtbiA9ICJzeXNOYW1lIikKCmgzN19hbm5vdCA8LSBsb2FkX21pY3JvYmVzb25saW5lX2Fubm90YXRpb25zKCJIMzdSdiIpCmgzN19nbyA8LSBsb2FkX21pY3JvYmVzb25saW5lX2dvKGlkID0gODMzMzIsIGlkX2NvbHVtbiA9ICJzeXNOYW1lIikKYGBgCgpUaGF0IGxvb2tzIHByZXR0eSByZWFzb25hYmxlIHRvIG1lLCBpdCBldmVuIGhhcyBDT0cgZ3JvdXBzIGFuZCBhbGwgdGhlCmZ1biBzdHVmZiBJIHdhbnQuCgojIyBXaGljaCBnZW5vbWUgYW0gSSB1c2luZz8KCkJlZm9yZSBJIHN0YXJ0LCBJIHNob3VsZCByZWNhbGwgd2hpY2ggaXMgbXkgY3VycmVudCByZWZlcmVuY2UgZ2Vub21lCmFuZCBzZWUgaWYgdGhlcmUgaXMgYSBiZXR0ZXIgYWx0ZXJuYXRpdmUgc2luY2UgbGFzdCBJIGxvb2tlZC4KCk15IGN1cnJlbnQgZ2Vub21lIGlzIHN0cmFpbiBIMzdSdiBsYXN0IGRvd25sb2FkZWQgaW4gMjAyMiwgaXQgaXMKZGVyaXZlZCBmcm9tIGFjY2Vzc2lvbiBOQ18wMDA5NjIuMyAvIGFzc2VtYmx5IEdDRl8wMDAxOTU5NTUuMi4KR2xhbmNpbmcgYXQgdGhlIGdmZiBmaWxlIEkgaGF2ZSwgSSBhbSBndWVzc2luZyB0aGF0IHRoZSBtb3N0CmFwcHJvcHJpYXRlIHRhZ3MgdG8gaW5kZXggYWdhaW5zdCBhcmUgZWl0aGVyIGxvY3VzX3RhZyhSdjAwMDMpIG9yCmdlbmUocmVjRikuCgpgYGB7YmFzaCwgZXZhbD1GQUxTRX0KY2QgcHJlcHJvY2Vzc2luZwpzdGFydD0kKHB3ZCkKZm9yIGkgaW4gJCgvYmluL2xzIC1kICogfCBncmVwIC12IFVuZGV0ZXIpOyBkbwogICAgY2QgJGkKICAgIGN5b2EgLS1tZXRob2QgcHJuYXNlcSAtLXNwZWNpZXMgbXR1YmVyY3Vsb3Npc19oMzdydiBcCiAgICAgICAgIC0tZ2ZmX3R5cGUgZ2VuZSAtLWdmZl90YWcgbG9jdXNfdGFnIFwKICAgICAgICAgLS1pbnRyb25zIDAgLS1mcmVlYmF5ZXMgMSBcCiAgICAgICAgIC0taW5wdXQgJCgvYmluL2xzICouZ3ogfCB0ciAnXG4nICc6JyB8IHNlZCAncy86JC8vZycpCiAgICBjZCAkc3RhcnQKZG9uZQpgYGAKCiMjIFRoZSBjb3JyZWN0IFN0cmFpbiBpcyBDREMxNTUxCgpPaywgc28gbGV0IHVzIHJlZG8gdGhpcyBhY2NvcmRpbmdseS4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQpjZCBwcmVwcm9jZXNzaW5nCnN0YXJ0PSQocHdkKQpmb3IgaSBpbiAkKC9iaW4vbHMgLWQgKiB8IGdyZXAgLXYgVW5kZXRlcik7IGRvCiAgICBjZCAkaQogICAgY3lvYSAtLW1ldGhvZCBwcm5hc2VxIC0tc3BlY2llcyBteWNvYmFjdGVyaXVtX3R1YmVyY3Vsb3Npc19jZGMxNTUxIFwKICAgICAgICAgLS1nZmZfdHlwZSBnZW5lIC0tZ2ZmX3RhZyBsb2N1c190YWcgXAogICAgICAgICAtLWludHJvbnMgMCAtLWZyZWViYXllcyAxIFwKICAgICAgICAgLS1pbnB1dCAkKC9iaW4vbHMgKi5neiB8IHRyICdcbicgJzonIHwgc2VkICdzLzokLy9nJykKICAgIGNkICRzdGFydApkb25lCmBgYAoKIyBPcnRob2xvZyBzZWFyY2ggb2YgQ0RDMTU1MS9IMzdSdgoKQSBmZXcgbWludXRlcyBhZ28gSSB3YXMgbWFraW5nIGEgY291cGxlIG9mIG5vdGVzIHRvIG15c2VsZiwgb25lIG9mCndoaWNoIHdhcyB0byBleHBsaWNpdGx5IG5vdGUgd2hlcmUgUGtuRiBpcyBpbiB0aGlzIHN0cmFpbi4gIFNhZGx5LAp3aGVuIEkgbG9va2VkIGludG8gdGhlIGFubm90YXRpb25zIEkgZG93bmxvYWRlZCBpdCB3YXMgdW5uYW1lZC4gIEkKd2FzIGFibGUgdG8gbWFrZSBhIGdvb2QgZ3Vlc3MgZ2l2ZW4gdGhhdCBJIGtuZXcgdGhlIGxvY2F0aW9uIGluIEgzN1J2CmFuZCBzYXcgYSBncm91cCBvZiBnZW5lcyBpbiBDREMxNTUxIGluIGJhc2ljYWxseSB0aGUgc2FtZSBwbGFjZSBpbiBhIHNpbWlsYXIKb3JpZW50YXRpb24uICBMYXRlciwgd2hlbiB0aGUgREUgZmluaXNoZWQgSSB3YXMgYWJsZSB0byBwcm92ZSBpdCBieQpzaG93aW5nIHRoYXQgTVQxNzg4IChwb3NpdGlvbiAxOTYyOTk2KSBpcyB0aGUgbW9zdCBkZWNyZWFzZWQgaW4gdGhlIM6UCnN0cmFpbiBhbmQgbW9zdCBpbmNyZWFzZWQgaW4gdGhlIGNvbXBsZW1lbnQuCgpXaXRoIHRoYXQgaW4gbWluZCwgSSB3YXMgYSBsaXR0bGUgc2FkIHRvIG5vdCBoYXZlIHRoZSBmdWxsIHNldCBvZgpIMzdSdiBhbm5vdGF0aW9ucyBhdmFpbGFibGUgYW5kIHNvIGFtIHNwaW5uaW5nIHVwIG15IGZhdm9yaXRlIG9ydGhvbG9nCnNlYXJjaCB0b29sICdvcnRob2ZpbmRlcicuICBUaGUgZm9sbG93aW5nIGJsb2NrIGlzIHdoZXJlIEkgYW0gZ29pbmcgdG8KZG8gdGhhdC4KCkkgZmlyc3QgbmVlZCB0byBleHRyYWN0IHRoZSBhbWlubyBhY2lkIHNlcXVlbmNlcyBmcm9tIEgzN1J2IChJIGhhdmUKdGhlbSBpbiBwbGFjZSBhbHJlYWR5IGZvciBDREMxNTUxKS4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQpta2RpciBvcnRob2xvZ3MKY2Qgb3J0aG9sb2dzCmNwIH4vbGlicmFyaWVzL2dlbm9tZS9tdHViKi5nYiAuCmNwIH4vbGlicmFyaWVzL2dlbm9tZS9teWNvKi5mYWEgLgpjeW9hIC0tbWV0aG9kIGdiMmdmZiAtLWlucHV0ICouZ2IKbHMgKi5mYWEKY3lvYSAtLW1ldGhvZCBvcnRob2ZpbmRlciAtLWlucHV0IG10dWJlcmN1bG9zaXNfaDM3cnYuZmFhOm15Y29iYWN0ZXJpdW1fdHViZXJjdWxvc2lzX2NkYzE1NTEuZmFhCmBgYAoKRm9yIHRoZSBjdXJpb3VzLCB0aGF0IGxhc3QgY29tbWFuZCBnZW5lcmF0ZXMgdGhlIGZvbGxvd2luZyBvbiB0aGUKY29tcHV0aW5nIGNsdXN0ZXI6CgpgYGB7YmFzaCwgZXZhbD1GQUxTRX0Kb3J0aG9maW5kZXIgLWYgb3V0cHV0cy81MG9ydGhvZmluZGVyL2lucHV0IFwKICAtbyBvdXRwdXRzLzUwb3J0aG9maW5kZXIvb3V0cHV0IFwKICAyPj5vdXRwdXRzLzUwb3J0aG9maW5kZXIvb3J0aG9maW5kZXIuc3RkZXJyIDE+Pm91dHB1dHMvNTBvcnRob2ZpbmRlci9vcnRob2ZpbmRlci5zdGRvdXQKbXYgb3V0cHV0cy81MG9ydGhvZmluZGVyL291dHB1dC9SZXN1bHRzX0RlYzA2Lyogb3V0cHV0cy81MG9ydGhvZmluZGVyL291dHB1dApybWRpciBvdXRwdXRzLzUwb3J0aG9maW5kZXIvb3V0cHV0L1Jlc3VsdHNfRGVjMDYKYGBgCgpJdCB3cml0ZXMgdGhlIGlucHV0IGZpbGUgZm9yIG1lIHNvIHRoYXQgSSBjYW5ub3QgaW50cm9kdWNlIGFueQphbm5veWluZyB0eXBlb2dyYXBoaWNhbCBlcnJyb3JzW3NpY10uICBJdCBhbHNvIGNyZWF0ZXMgYSBsaXR0bGUgam9iCnRoYXQgcGFyc2VzIHRoZSBxdWl0ZSBjb25mdXNpbmcgb3V0cHV0cyBmcm9tIG9ydGhvZmluZGVyIGludG8gYW4KKGhvcGVmdWxseSkgZWFzeSB0byByZWFkIHRhYmxlLgoKTXkgaG9wZSBpcyB0byBzaG9ydGx5IGJlIGFibGUgdG8gYXBwZW5kIGFsbCB0aGUgSDM3UnYgSURzIHRvIG15CmFubm90YXRpb24gc2V0IGZvciBDREMxNTUxLiAgV2Ugc2hhbGwgc2VlLCBvcnRob2ZpbmRlciB0YWtlcyB+IDEwCm1pbnV0ZXMgLyAxMDAwIGdlbmVzLgoKIyMjIFJlYWQgaW4gb3J0aG9ncm91cCBpbmZvcm1hdGlvbgoKVGhlIG9ydGhvbG9ncyBwcm9kdWNlZCBieSBvcnRob2ZpbmRlciBhcHBlYXIgdG8gcGljayB1cCBzaW5nbGUtZ3JvdXBzCmZvciAzMzQzIGdlbmVzLCB3aGljaCBzZWVtcyBwcmV0dHkgZ29vZCwgSSBhbSBhc3N1bWluZyB0aGUgcmVtYWluZGVyCm9mIGdlbmVzIGFyZSBtdWx0aS1nZW5lIGZhbWlsaWVzIHdoaWNoIHdpbGwgYWxzbyBiZSBuaWNlbHkgaWRlbnRpZmllZC4KCmBgYHtyfQpzaW5nbGVfb3J0aG9sb2dzIDwtIGFzLmRhdGEuZnJhbWUocmVhZHI6OnJlYWRfdHN2KCJvcnRob2xvZ3Mvb3V0cHV0cy81MG9ydGhvZmluZGVyL29ydGhvZ3JvdXBzX3NpbmdsZV9uYW1lZC50c3YiKSkKcm93bmFtZXMoc2luZ2xlX29ydGhvbG9ncykgPC0gc2luZ2xlX29ydGhvbG9nc1tbIk9ydGhvZ3JvdXAiXV0Kc2luZ2xlX29ydGhvbG9ncyA8LSBzaW5nbGVfb3J0aG9sb2dzWywgYygyLCA0KV0KY29sbmFtZXMoc2luZ2xlX29ydGhvbG9ncykgPC0gYygiaDM3cnYiLCAiY2RjMTU1MSIpCgojIyBUaGVyZSBhcmUgYSBidW5jaCBvZiAxOm1hbnkgbWFwcGluZ3MgYW5kIG1hbnk6bWFueSBtYXBwaW5ncyBpdCB0dXJucyBvdXQhCiMjIGFuZCBJIG5lZWQgdG8gcmVmb3JtYXQgdGhlIHRleHQgZmlsZSBjb250YWluaW5nIHRoZW0sIHN1cGlkbyBvcnRob2ZpbmRlcgojIyBhZGRlZCBzb21lIHJhbmRvbSBjaGFyYWN0ZXJzIGluIHRoZSBsaXN0cyBvZiBnZW5lcyB3aGljaCBtYWtlIGl0IHdlaXJkIHRvIHBhcnNlLgphbGxfb3J0aG9ncm91cHMgPC0gYXMuZGF0YS5mcmFtZShyZWFkcjo6cmVhZF90c3YoIm9ydGhvbG9ncy9vdXRwdXRzLzUwb3J0aG9maW5kZXIvb3J0aG9ncm91cHNfYWxsX25hbWVkLnRzdiIpKQpgYGAKCk9rLCBzbyBJIG5lZWQgdG8gZG8gYSBsaXR0bGUgd29yayB0byBjbGVhbiB1cCB0aGUgKDF8bWFueSk6KDF8bWFueSkKbWFwcGluZ3M7IHVudGlsIHRoZW4gbGV0IHVzIGp1c3QgbWVyZ2UgdGhlIDE6MSBtYXBwaW5ncyBpbnRvIHRoZQpDREMxNTUxIGFubm90YXRpb25zLgoKSSB0aGluayBJIHdpbGwgbmVlZCB0byBnZXQgdGhlIE5JSCBJRHMgZnJvbSB0aGUgZ2VuYmFuayBvciBnZmYgZmlsZQpiZWZvcmUgbWVyZ2luZyB0byB0aGUgbWljcm9iZXNvbmxpbmUgYW5ub3RhdGlvbnMuICBBbiBpbXBvcnRhbnQgY2F2ZWF0CkkgZGlkIG5vdCBjb25zaWRlciBiZWZvcmU6IHRoZSBvcnRob2xvZyBzZWFyY2hlcyB3ZXJlIGV4cGxpY2l0bHkgb24KQ0RTL3Byb3RlaW5zIGFuZCBteSBnZW5lcmFsIGFubm90YXRpb25zIGFyZSBub3QuCgpgYGB7cn0KaDM3X2NkcyA8LSBsb2FkX2dmZl9hbm5vdGF0aW9ucygib3J0aG9sb2dzL210dWJlcmN1bG9zaXNfaDM3cnZfYWxsLmdmZiIsIHR5cGUgPSAiQ0RTIikKCmgzN19jZHNfc2luZ2xlcyA8LSBtZXJnZShoMzdfY2RzLCBzaW5nbGVfb3J0aG9sb2dzLCBieS54ID0gInByb3RlaW5faWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYnkueSA9ICJoMzdydiIsIGFsbC54ID0gVFJVRSkKCmNkY19jZHMgPC0gbG9hZF9nZmZfYW5ub3RhdGlvbnMoIm9ydGhvbG9ncy9teWNvYmFjdGVyaXVtX3R1YmVyY3Vsb3Npc19jZGMxNTUxX2Nkcy5nZmYiLCB0eXBlID0gIkNEUyIpCmgzN19uY2JpX2NkYyA8LSBtZXJnZShoMzdfY2RzX3NpbmdsZXMsIGNkY19jZHMsIGJ5LnggPSAiY2RjMTU1MSIsIGJ5LnkgPSAicHJvdGVpbl9pZCIpCgpzaW5nbGVfZ2VuZV9tYXBwaW5nIDwtIGgzN19uY2JpX2NkY1ssIGMoImxvY3VzX3RhZy54IiwgImxvY3VzX3RhZy55IiwgImdlbmUueCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJvZHVjdC54IiwgImdlbmUueSIsICJwcm9kdWN0LnkiKV0KY29sbmFtZXMoc2luZ2xlX2dlbmVfbWFwcGluZykgPC0gYygiaDM3cnZfdGFnIiwgImNkYzE1NTFfdGFnIiwgImgzN19nZW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaDM3X3Byb2R1Y3QiLCAiY2RjX2dlbmUiLCAiY2RjX3Byb2R1Y3QiKQpgYGAKCiMjIEFkZCB0aGUgc2luZ2xlIGdlbmUgbWFwcyB0byB0aGUgYW5ub3RhdGlvbnMKCk9oLCB0aGUgd2F5IEkgZGlkIHRoZSBhYm92ZSwgdGhpcyB3aWxsIGFsbW9zdCBjZXJ0YWlubHkgZW5kIHVwIHdpdGgKcmVkdW5kYW50IGNvbHVtbnM7IGJ1dCBzaW5jZSB0aG9zZSBjb2x1bW5zIGFyZSBjb21pbmcgZnJvbSBkaWZmZXJlbnQKc291cmNlcyBpdCB3aWxsIGJlIGEgZ29vZCBjb250cm9sIHRvIGVuc3VyZSB0aGF0IGV2ZXJ5dGhpbmcgd29ya2VkCnByb3Blcmx5IChlLmcuIGlmIHRoZXkgcHJvdmUgbm90IHRvIGJlIHJlZHVuZGFudCB0aGVuIHdlIGtub3cgdGhlcmUKd2VyZSBzaGVuYW5pZ2FucyBpbiBteSBvcnRob2xvZyBtYXBwaW5nKS4KCmBgYHtyfQphbm5vdCA8LSBtZXJnZShhbm5vdCwgc2luZ2xlX2dlbmVfbWFwcGluZywgYnkueCA9ICJyb3cubmFtZXMiLAogICAgICAgICAgICAgICBieS55ID0gImNkYzE1NTFfdGFnIiwgYWxsLnggPSBUUlVFKQpyb3duYW1lcyhhbm5vdCkgPC0gYW5ub3RbWyJSb3cubmFtZXMiXV0KYW5ub3RbWyJSb3cubmFtZXMiXV0gPC0gTlVMTApgYGAKCiMgQSBzbGlnaHRseSByYW5kb20gYXNpZGUsIHJSTkEgYW5kIDZTCgpHaXZlbiB0aGUgcGVjdWxhcml0aWVzIHdlIG9ic2VydmVkIHZpcyBhIHZpcyB0aGUgUHNldWRvbW9uYXMgcmVhZHMsCnRoZXJlIGlzIGV4cGxpY2l0IGludGVyZXN0IGZyb20gQXByaWwgdG8ga25vdyBob3cgd2VsbCB0aGUgcmlib3NvbWFsCmRlcGxldGlvbiB3ZW50OyBzbyBJIGRpZCBhIGxpdHRsZSBwb2tpbmcgYW5kIGZvdW5kIHRoYXQgdGhlIHJpYm9zb21hbApnZW5lcyBhcmUgbmFtZWQgcnJmKDVTKSwgcnJzKDE2UyksIGFuZCBycmwoMjNTKS4gIFdoZW4gSSBtYWtlIGEKYmFjdGVyaWFsIHJpYm9zb21hbCBkYXRhYmFzZSBJIHVzdWFsbHkgbGlrZSB0byBpbmNsdWRlIGEgZmV3IHRSTkFzIGFuZCA2UywgZXZlbgp0aG91Z2ggNVMvNlMvdFJOQXMgc2hvdWxkIGJlIHNpemUtc2VsZWN0ZWQgb3V0IG9mIHRoZSBsaWJyYXJpZXMgcHJldHR5CmNvbnNpc3RlbnRseS4gIEl0IHR1cm5zIG91dCB0aGUgYmlvbG9neSBvZiBSTkFzIHdoaWNoIGludGVyYWN0IHdpdGgKz4MgaW4gTXRiIGlzIGtpbmQgb2Ygd2lsZCBhbmQgdGhlcmUgaXMgbm8ga25vd24gNnMsIGJ1dCBhIHNvbWV3aGF0CnNpbWlsYXIgUk5BIG5hbWVkICdNczEnLgoKQW55aG93LCBJIG1hZGUgYSByUk5BIGRhdGFiYXNlIGZvciBNdGIgYW5kIGhlcmUgaXMgYSBxdWVyeSBhZ2FpbnN0IGl0CnRvIGdldCBhIHNlbnNlIG9mIGxpa2VseSByUk5BIHJlYWRzIGluIHRoZSBzYW1wbGVzLgoKYGBge2Jhc2gsIGV2YWw9RkFMU0V9CmNkIHByZXByb2Nlc3NpbmcKc3RhcnQ9JChwd2QpCmZvciBpIGluICQoL2Jpbi9scyAtZCAqIHwgZ3JlcCAtdiBVbmRldGVybWluZWQpOyBkbwogICAgY2QgJGkKICAgIGN5b2EgLS1tZXRob2QgaGlzYXQgLS1saWJ0eXBlIHJSTkEgLS1zcGVjaWVzIG10dWJlcmN1bG9zaXNfaDM3cnYgXAogICAgICAgICAtLWlucHV0ICQoL2Jpbi9scyAqLXRyaW1tZWQuZmFzdHEueHogfCB0ciAnXG4nICc6JyB8IHNlZCAncy86JC8vZycpCiAgICBjZCAkc3RhcnQKZG9uZQpgYGAKCiMgQXBwZW5kIGluZm9ybWF0aW9uIHRvIHRoZSBzYW1wbGUgc2hlZXQKCldlIGhhdmUgYSByZWxhdGl2ZWx5IHNwYXJzZSBzYW1wbGUgc2hlZXQgdG8gc3RhcnQgd2l0aCwgbGV0cyBhZGQgc29tZQpzdW1tYXJ5IHN0YXRzIGZyb20gY3lvYSB0byBpdC4KClRoZXJlIGlzIG9uZSBpbXBvcnRhbnQgcGllY2Ugb2YgaW5mb3JtYXRpb24gdGhhdCBEYW5pZWwgYWxlcnRlZCBtZSB0bwp3aGljaCBpcyBub3QgaW5jbHVkZWQgaW4gdGhlIGdhdGhlcmVkIG1ldGFkYXRhIChJIHRoaW5rKTogdGhlc2UKc2FtcGxlcyBhcHBlYXIgdG8gaGF2ZSBhbiBleHRyYW9yaW5kYXJpbHkgbGFyZ2UgYW1vdW50IG9mIHBvdGVudGlhbGx5Cm90aGVyIGJhY3RlcmlhbCBzZXF1ZW5jZSBpbiB0aGVtOyBhbmQgaXQgYXBwZWFycyB0byBiZSBkb21pbmF0ZWQgYnkKUHNldWRvbW9uYXMgYWVydWdpbm9zYSAtLSBJIGFtIGFzc3VtaW5nIFBBMDEgYW5kIHdpbGwgdHJ5IG1hcHBpbmcgdGhlCnJlYWRzIGFnYWluc3QgdGhhdCBzdHJhaW4gdG8gc2VlIHdoYXQgaXMgZ29pbmcgb24uCgpVbnRpbCB0aG9zZSBtYXBwaW5ncyBhcmUgY29tcGxldGUsIEkgd2lsbCBjb250aW51ZSBvbiBhcyBub3JtYWwsIGJ1dAprZWVwIGluIG1pbmQgdGhhdCB0aGUgZm9sbG93aW5nIHdpbGwgYWxtb3N0IGNlcnRhaW4gbmVlZCB0byBjaGFuZ2UuCgpgYGB7cn0Kc3BlYyA8LSBtYWtlX3JuYXNlcV9zcGVjKCkKZ2F0aGVyZWQgPC0gZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoInNhbXBsZV9zaGVldHMvYWxsX3NhbXBsZXMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2llcyA9ICJteWNvYmFjdGVyaXVtX3R1YmVyY3Vsb3Npc19jZGMxNTUxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWZpY2F0aW9uID0gc3BlYykKYGBgCgojIENyZWF0ZSBhbiBleHByZXNzaW9uc2V0CgpgYGB7cn0KZXhwdCA8LSBjcmVhdGVfZXhwdChnYXRoZXJlZFtbIm5ld19maWxlIl1dLCBnZW5lX2luZm8gPSBhbm5vdCwgZmlsZV9jb2x1bW4gPSAiaGlzYXRjb3VudHRhYmxlIikKCndyaXR0ZW4gPC0gd3JpdGVfZXhwdChleHB0LCBleGNlbCA9IGdsdWUoImV4Y2VsL2FsbF9zYW1wbGVzLXZ7dmVyfS54bHN4IikpCmBgYAoKIyBQb2tlIGF0IGl0CgpgYGB7cn0KcGxvdF9saWJzaXplKGV4cHQpCnBsb3Rfbm9uemVybyhleHB0KQoKbm9ybSA8LSBub3JtYWxpemVfZXhwdChleHB0LCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnBsb3RfY29yaGVhdChub3JtKQpwbG90X2Rpc2hlYXQobm9ybSkKcGxvdF9wY2Eobm9ybSkKCm5iIDwtIG5vcm1hbGl6ZV9leHB0KGV4cHQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9ICJsaW1tYSIsIGZpbHRlciA9IFRSVUUpCnBsb3RfcGNhKG5iKQoKbnMgPC0gbm9ybWFsaXplX2V4cHQoZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsIGJhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCnBsb3RfcGNhKG5zKQpgYGAKCldlbGwsIHRoYXQgaXMgbm90IGdyZWF0LiAgSSBhcmJpdHJhcmlseSB0cmllZCBhIGJhdGNoIGluIG1vZGVsIGFuZCBzdmEKYWRqdXN0bWVudCwgYnV0IGFtIG5vdCBpbmNsdWRpbmcgdGhlbSB3aXRob3V0IGZ1cnRoZXIgaW5mb3JtYXRpb24uCgojIyBDaGVjayB0aGUgclJOQSBjb250ZW50CgpUaGUgZm9sbG93aW5nIGRvZXMgbm90IHdvcmsgYmVjYXVzZSBJIGZlbGwgaW50byB0aGUgYXNzdW1wdGlvbiB0aGF0CnRoZXNlIGFyZSBIMzdSdiBzYW1wbGVzIGFnYWluISAgRG9vZnVzLgoKSSBndWVzcyBJIGNvdWxkIHB1bGwgdGhlIElEcyBiZWNhdXNlIEkgbWF0Y2hlZCB0aGVtIGFnYWluc3QgSDM3UnY7CmJ1dCBJIGFsc28gbWFwcGVkIGFnYWluc3QgSDM3UnYsIHNvIEkgY291bGQganVzdCB1c2UgdGhhdC4KCmBgYHtyLCBldmFsPUZBTFNFfQpycm5hX2xvY2kgPC0gYygiUnZucjAxIiwgIlJ2bnIwMiIsICJSdm5yMDMiKQpycm5hX2V4cHQgPC0gZXhwdFtycm5hX2xvY2ksIF0KYGBgCgpXaGlsZSBJIHdhcyB0eXBpbmcgdGhlIGFib3ZlIGluY29ycmVjdGx5LCB0aGUgYWxpZ25tZW50cyBzdGFydGVkCmZpbmlzaGluZyB0aGUgcXVlcnkgYWdhaW5zdCBteSBNdGIgclJOQSBkYXRhYmFzZS4gIEl0IGxvb2tzIGxpa2UgfiAzJQpvZiB0aGUgcmVhZHMgbWFwIHRvIHJSTkEuCgojIHZhcnBhcnQKCmBgYHtyfQp2YXJwYXJ0IDwtIHNpbXBsZV92YXJwYXJ0KGV4cHQpCnZhcnBhcnQKYGBgCgojIEtyYWtlbiBtYXRyaXgKCmBgYHtyfQpnZW51c19leHB0IDwtIGNyZWF0ZV9leHB0KGdhdGhlcmVkW1sibmV3X2ZpbGUiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAia3Jha2VubWF0cml4IiwgZmlsZV90eXBlID0gInRhYmxlIikKZ2VudXNfbm9ybSA8LSBub3JtYWxpemVfZXhwdChnZW51c19leHB0LCBjb252ZXJ0ID0gImNwbSIpCnBsb3RfZGlzaGVhdChnZW51c19ub3JtKQpnZW51c19ub3JtdjIgPC0gbm9ybWFsaXplX2V4cHQoZ2VudXNfZXhwdCwgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIpCnBsb3RfcGNhKGdlbnVzX25vcm12MikKcGxvdF9saWJzaXplKGdlbnVzX2V4cHQpCmhlYWQoZXhwcnMoZ2VudXNfZXhwdCkpCmV4cHJzKGdlbnVzX2V4cHQpWyJQc2V1ZG9tb25hcyIsIF0KYGBgCgojIERpZmZlcmVudGlhbCBFeHByZXNzaW9uCgpJIGFtIGdvaW5nIHRvIGFzc3VtZSBmb3IgdGhlIG1vbWVudCB0aGF0IHdlIGNhbiBsZWFybiBpbnRlcmVzdGluZwp0aGluZ3MgZnJvbSB0aGUgZGF0YSwgYnV0IHRoYXQgaXQgd2lsbCByZXF1aXJlIG1vcmUgaW50ZXJ2ZW50aW9uIHRoYW4KdXN1YWwgZm9yIGEgYmFjdGVyaWFsIGRhdGFzZXQuCgpgYGB7cn0Ka2VlcGVycyA8LSBsaXN0KAogICJkZWx0YV93dCIgPSBjKCJkZWx0YSIsICJ3dCIpLAogICJjb21wX3d0IiA9IGMoImNvbXBsZW1lbnQiLCAid3QiKSwKICAiZGVsdGFfY29tcCIgPSBjKCJkZWx0YSIsICJjb21wbGVtZW50IikpCmRlIDwtIGFsbF9wYWlyd2lzZShleHB0LCBrZWVwZXJzID0ga2VlcGVycywgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikKdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIGRlLCBrZWVwZXJzID0ga2VlcGVycywgZXhjZWwgPSBnbHVlKCJleGNlbC9kZV90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgdGFibGVzLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLCBleGNlbCA9IGdsdWUoImV4Y2VsL2RlX3NpZy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIEFsc28gcHJvdmlkZSBhIGxlc3Mgc3RyaW5nZW50IHZlcnNpb24KCmBgYHtyfQpsZXNzX3N0cmluZ2VudCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIHRhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwgbGZjID0gMC42LCBwID0gMSwKICBleGNlbCA9IGdsdWUoImV4Y2VsL2RlX3NpZ18wLjZsZmNfMS4wcHZhbC12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBUZXN0IGJhdGNoLWluLW1vZGVsCgpHaXZlbiB0aGUgUENBIGFib3ZlLCBpdCBzZWVtcyBhdCBsZWFzdCBwb3NzaWJsZSB0aGF0IGluY2x1ZGluZyBiYXRjaAppbiBtb2RlbCBtaWdodCBwcm92aWRlIG1vcmUgcmVsaWFibGUgcmVzdWx0cyB0aGFuIHN2YS4gIFNvLCB0aGUKZm9sbG93aW5nIGJsb2NrIGRvZXMgdGhhdC4gIFNwb2lsZXIgYWxlcnQ6IEkgZG9uJ3QgdGhpbmsgaXQgaGVscGVkLgoKYGBge3J9CmRlX2JhdGNoIDwtIGFsbF9wYWlyd2lzZShleHB0LCBrZWVwZXJzID0ga2VlcGVycywgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSBUUlVFKQpkZV9iYXRjaAp0YWJsZXNfYmF0Y2ggPC0gY29tYmluZV9kZV90YWJsZXMoZGVfYmF0Y2gsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlKCJleGNlbC9kZV90YWJsZXNfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKdGFibGVzX2JhdGNoCnNpZ19iYXRjaCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKHRhYmxlc19iYXRjaCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlKCJleGNlbC9kZV9zaWdfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKc2lnX2JhdGNoCmBgYAoKIyMgVGhlIGludGVyc2VjdGlvbiBvZiDOlC9XVCBhbmQgzpQvY29tcAoKYGBge3J9CmxpYnJhcnkoVXBTZXRSKQpmaXJzdF91cCA8LSBzaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImRlbHRhX3d0Il1dCnNlY29uZF91cCA8LSBzaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImRlbHRhX2NvbXAiXV0KCmZpcnN0X2Rvd24gPC0gc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImRlbHRhX3d0Il1dCnNlY29uZF9kb3duIDwtIHNpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJkZWx0YV9jb21wIl1dCgpjb21wYXJpc29uIDwtIGxpc3QoCiAgImRfd191cCIgPSByb3duYW1lcyhmaXJzdF91cCksCiAgImRfY191cCIgPSByb3duYW1lcyhzZWNvbmRfdXApLAogICJkX3dfZG93biIgPSByb3duYW1lcyhmaXJzdF9kb3duKSwKICAiZF9jX2Rvd24iID0gcm93bmFtZXMoc2Vjb25kX2Rvd24pKQpxdWVyeSA8LSBVcFNldFI6OmZyb21MaXN0KGNvbXBhcmlzb24pCnNldHMgPC0gVXBTZXRSOjp1cHNldChxdWVyeSkKc2V0cwojIyBTbywgdGhlcmUgYXJlIDIgc2hhcmVkIGRvd24gYW5kIDEyIHVwLiAgQWxzbyAxIHdlaXJkbyAod2hpY2ggZ2l2ZW4KIyMgaXRzIHByb3hpbWl0eSB0byB0aGUgb3Blcm9uIGNvbnRhaW5pbmcgUGtuRiBpcyBsaWtlbHkgaW50ZXJlc3RpbmcpCgpvdmVybGFwX2lkcyA8LSBvdmVybGFwX2dyb3Vwcyhjb21wYXJpc29uKQppbnRlcmVzdGluZ191cCA8LSBvdmVybGFwX2dlbmVpZHMob3ZlcmxhcF9pZHMsICJkX3dfdXA6ZF9jX3VwIikKaW50ZXJlc3RpbmdfdXAKCmludGVyZXN0aW5nX2Rvd24gPC0gb3ZlcmxhcF9nZW5laWRzKG92ZXJsYXBfaWRzLCAiZF93X2Rvd246ZF9jX2Rvd24iKQppbnRlcmVzdGluZ19kb3duCgp3ZWlyZG8gPC0gb3ZlcmxhcF9nZW5laWRzKG92ZXJsYXBfaWRzLCAiZF93X3VwOmRfY19kb3duIikKd2VpcmRvCgpvdmVybGFwcGluZ19tZXRhIDwtIGFubm90W2MoaW50ZXJlc3RpbmdfdXAsIGludGVyZXN0aW5nX2Rvd24sIHdlaXJkbyksIF0Kd3JpdHRlbiA8LSB3cml0ZV94bHN4KG92ZXJsYXBwaW5nX21ldGEsIGV4Y2VsID0gImV4Y2VsL292ZXJsYXBwaW5nX3N0cmluZ2VudF9nZW5lcy54bHN4IikKYGBgCgojIyBSZXBlYXQgdGhlIGludGVyc2VjdGlvbiBvZiDOlC9XVCBhbmQgzpQvY29tcCB3aXRoIHRoZSBsZXNzIHNpZ25pZmljYW50IGRhdGEKCmBgYHtyfQpmaXJzdF91cCA8LSBsZXNzX3N0cmluZ2VudFtbImRlc2VxIl1dW1sidXBzIl1dW1siZGVsdGFfd3QiXV0Kc2Vjb25kX3VwIDwtIGxlc3Nfc3RyaW5nZW50W1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJkZWx0YV9jb21wIl1dCgpmaXJzdF9kb3duIDwtIGxlc3Nfc3RyaW5nZW50W1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImRlbHRhX3d0Il1dCnNlY29uZF9kb3duIDwtIGxlc3Nfc3RyaW5nZW50W1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImRlbHRhX2NvbXAiXV0KCmNvbXBhcmlzb24gPC0gbGlzdCgKICAiZF93X3VwIiA9IHJvd25hbWVzKGZpcnN0X3VwKSwKICAiZF9jX3VwIiA9IHJvd25hbWVzKHNlY29uZF91cCksCiAgImRfd19kb3duIiA9IHJvd25hbWVzKGZpcnN0X2Rvd24pLAogICJkX2NfZG93biIgPSByb3duYW1lcyhzZWNvbmRfZG93bikpCnF1ZXJ5IDwtIFVwU2V0Ujo6ZnJvbUxpc3QoY29tcGFyaXNvbikKc2V0cyA8LSBVcFNldFI6OnVwc2V0KHF1ZXJ5KQpzZXRzCiMjIFNvLCB0aGVyZSBhcmUgMiBzaGFyZWQgZG93biBhbmQgMTIgdXAuICBBbHNvIDEgd2VpcmRvICh3aGljaCBnaXZlbgojIyBpdHMgcHJveGltaXR5IHRvIHRoZSBvcGVyb24gY29udGFpbmluZyBQa25GIGlzIGxpa2VseSBpbnRlcmVzdGluZykKCm92ZXJsYXBfaWRzIDwtIG92ZXJsYXBfZ3JvdXBzKGNvbXBhcmlzb24pCmludGVyZXN0aW5nX3VwIDwtIG92ZXJsYXBfZ2VuZWlkcyhvdmVybGFwX2lkcywgImRfd191cDpkX2NfdXAiKQppbnRlcmVzdGluZ191cAoKaW50ZXJlc3RpbmdfZG93biA8LSBvdmVybGFwX2dlbmVpZHMob3ZlcmxhcF9pZHMsICJkX3dfZG93bjpkX2NfZG93biIpCmludGVyZXN0aW5nX2Rvd24KCndlaXJkbyA8LSBvdmVybGFwX2dlbmVpZHMob3ZlcmxhcF9pZHMsICJkX3dfdXA6ZF9jX2Rvd24iKQp3ZWlyZG8KCm92ZXJsYXBwaW5nIDwtIGFzLmNoYXJhY3RlcihjKGludGVyZXN0aW5nX3VwLCBpbnRlcmVzdGluZ19kb3duLCB3ZWlyZG8pKQoKb3ZlcmxhcHBpbmdfbWV0YSA8LSBhbm5vdFtjKGludGVyZXN0aW5nX3VwLCBpbnRlcmVzdGluZ19kb3duLCB3ZWlyZG8pLCBdCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChvdmVybGFwcGluZ19tZXRhLCBleGNlbCA9ICJleGNlbC9vdmVybGFwcGluZ19sZXNzX3N0cmluZ2VudF9nZW5lcy54bHN4IikKYGBgCgojIE9udG9sb2d5IGVucmljaG1lbnQKCkdpdmVuIHRoZSByZWxhdGl2ZSBzcGFyc2l0eSBvZiB0aGUgYW5ub3RhdGlvbnMgZm9yIENEQzE1NTEsIEkgbWlnaHQKZWl0aGVyIGdvIGJhY2sgdG8gbXkgSDM3UnYgbWFwcGluZyBkYXRhICh3aGljaCB3YXMgcHJldHR5IGRlY2VudCksIG9yCnVzZSB0aGUgb3J0aG9sb2dzIGFuZCB0aGVpciBhbm5vdGF0aW9uczsgYnV0IHNpbmNlIEkgYWxyZWFkeSBoYXZlIHRoZQpkYXRhIGluIGl0cyBjdXJyZW50IGZvcm0gbG9hZGVkLCBsZXQgdXMganVzdCB0cnkgaXQgYW5kIHNlZS4KCiMjIFZvbGtlcidzIGV4cGxpY2l0IHF1ZXJ5IGZpcnN0CgpUaGVyZSBhcmUgb25seSAxNSBnZW5lcyBpbiB0aGUgc2V0IG9mIGludGVyZXN0aW5nIGludGVyc2VjdGlvbnM7IHNvIEkKYW0gZ29pbmcgdG8gZ3JvdXAgdGhlbSB0b2dldGhlci4KCkluIG15IGFubm90YXRpb24gYmxvY2sgYWJvdmUgSSBkb3dubG9hZGVkIHRoZSBIMzdSdiBhbmQgQ0RDMTU1MQphbm5vdGF0aW9ucy9HTyBjYXRlZ29yaWVzLiAgVGhlcmUgYXBwZWFycyB0byBiZSBhIGJ1ZyBpbiB0aGUgR08KbG9hZGVyLCBpdCBuZWVkZWQgdGhlIGFjdHVhbCBJRCBudW1iZXIgaW5zdGVhZCBvZiBhIHVuaXF1ZSBzdHJpbmcgbGlrZQp0aGUgYW5ub3RhdGlvbnM7IGhhcHBpbHkgdGhlIGFubm90YXRpb24gbG9hZCBwcmludHMgb3V0IHRoZSBJRCBudW1iZXIKc28gSSBkaWQgbm90IGhhdmUgdG8gdGhpbmsgdmVyeSBoYXJkLgoKIyMjIExlbmd0aCBhbmQgQ09HIGRhdGFiYXNlcwoKSSBmb3Jnb3QgZm9yIGEgY291cGxlIHdlZWtzIHRvIHBlcmZvcm0gdGhlIHNhbWUgb3ZlcnJlcHJlc2VudGF0aW9uCmFuYWx5c2VzIHVzaW5nIHRoZSBDT0cgZnVuY3Rpb24gYXNzaWdubWVudHMuICBMZXQgdXMgY3JlYXRlIHRoYXQKYXNzb2NpYXRpb24gdGFibGUgaGVyZSBhbmQgYWRkIHRoZSBnb3NlcSBzZWFyY2hlcyBiZWxvdy4KCmBgYHtyfQphbm5vdFtbImxlbmd0aCJdXSA8LSBhYnMoYW5ub3RbWyJzdGFydCJdXSAtIGFubm90W1sic3RvcCJdXSkKbGVuZ3RoX2RiIDwtIGFzLmRhdGEuZnJhbWUoYW5ub3RbLCBjKCJuYW1lIiwgImxlbmd0aCIpXSkKY29sbmFtZXMobGVuZ3RoX2RiKSA8LSBjKCJJRCIsICJsZW5ndGgiKQoKc3RhcnRfY29nX2RmIDwtIGFubm90WywgYygiZGVzYyIsICJDT0ciLCAiQ09HRnVuIiwgIkNPR0Rlc2MiLCAiVElHUkZhbSIsICJUSUdSUm9sZXMiKV0Kc3RhcnRfY29nX2RmW1siSUQiXV0gPC0gcm93bmFtZXMoc3RhcnRfY29nX2RmKQpjb2dfZGYgPC0gc3RhcnRfY29nX2RmWywgYygiSUQiLCAiQ09HRnVuIildCmNvbG5hbWVzKGNvZ19kZikgPC0gYygiSUQiLCAiR08iKQpgYGAKCiMjIFRoZSBvbnRvbG9neSBzZWFyY2hlcwoKYGBge3J9CnF1ZXJ5X2dlbmVzIDwtIHVuaXF1ZShjKGludGVyZXN0aW5nX3VwLCBpbnRlcmVzdGluZ19kb3duLCB3ZWlyZG8pKQoKZ29zZXFfcXVlcnkgPC0gc2ltcGxlX2dvc2VxKHF1ZXJ5X2dlbmVzLCBnb19kYiA9IGdvX2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2RiID0gbGVuZ3RoX2RiLCBtaW5feHJlZiA9IDQpCmdvc2VxX3F1ZXJ5Cgpjb2dfcXVlcnkgPC0gc2ltcGxlX2dvc2VxKHF1ZXJ5X2dlbmVzLCBnb19kYiA9IGNvZ19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICBleHBhbmRfY2F0ZWdvcmllcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9kYiA9IGxlbmd0aF9kYiwgbWluX3hyZWYgPSAzKQpgYGAKCiMjIyBTYW1lIHRoaW5nLCBsZXNzIHN0cmluZ2VudAoKYGBge3J9Cmdvc2VxX3F1ZXJ5IDwtIHNpbXBsZV9nb3NlcSh1bmlxdWUob3ZlcmxhcHBpbmcpLCBnb19kYiA9IGdvX2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2RiID0gbGVuZ3RoX2RiLCBtaW5feHJlZiA9IDQpCmdvc2VxX3F1ZXJ5CndyaXR0ZW4gPC0gd3JpdGVfZ29zZXFfZGF0YShnb3NlcV9xdWVyeSwgZXhjZWwgPSAiZXhjZWwvZ29zZXFfbGVzc19zdHJpbmdlbnRfcmVzdWx0cy54bHN4IikKCnRvcGdvX3F1ZXJ5IDwtIHNpbXBsZV90b3Bnbyh1bmlxdWUob3ZlcmxhcHBpbmcpLCBleGNlbCA9ICJleGNlbC90b3Bnb19sZXNzX3N0cmluZ2VudF9yZXN1bHRzLnhsc3giKSkKYGBgCgpHaXZlbiB0aGF0IHRoZXJlIGFyZSBvbmx5IGEgZmV3IGdlbmVzIGluIHRoZSBhYm92ZSBxdWVyeSwgbGV0IHVzIGFsc28KZG8gdGhlIHRocmVlIHByaW1hcnkgY29udHJhc3RzIHNlcGFyYXRlbHkgYXMgSSB0aGluayB0aGV5IHdpbGwgcHJvdmUKbW9yZSBpbnRlcmVzdGluZy4KCmBgYHtyfQpnb3NlcV91cF9kZWx0YV93dCA8LSBzaW1wbGVfZ29zZXEoc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJkZWx0YV93dCJdXSwgZ29fZGIgPSBnb19kYiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9kYiA9IGxlbmd0aF9kYikKZ29zZXFfdXBfZGVsdGFfd3QKCmdvc2VxX2Rvd25fZGVsdGFfd3QgPC0gc2ltcGxlX2dvc2VxKHNpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJkZWx0YV93dCJdXSwgZ29fZGIgPSBnb19kYiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2RiID0gbGVuZ3RoX2RiKQpnb3NlcV9kb3duX2RlbHRhX3d0CgoKZ29zZXFfdXBfY29tcF93dCA8LSBzaW1wbGVfZ29zZXEoc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJjb21wX3d0Il1dLCBnb19kYiA9IGdvX2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2RiID0gbGVuZ3RoX2RiLCBtaW5feHJlZiA9IDIwKQpnb3NlcV91cF9jb21wX3d0Cgpnb3NlcV9kb3duX2NvbXBfd3QgPC0gc2ltcGxlX2dvc2VxKHNpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJjb21wX3d0Il1dLCBnb19kYiA9IGdvX2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfZGIgPSBsZW5ndGhfZGIsIG1pbl94cmVmID0gNSkKZ29zZXFfZG93bl9jb21wX3d0CgoKZ29zZXFfdXBfZGVsdGFfY29tcCA8LSBzaW1wbGVfZ29zZXEoc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJkZWx0YV9jb21wIl1dLCBnb19kYiA9IGdvX2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfZGIgPSBsZW5ndGhfZGIsIG1pbl94cmVmID0gMTApCmdvc2VxX3VwX2RlbHRhX2NvbXAKCmdvc2VxX2Rvd25fZGVsdGFfY29tcCA8LSBzaW1wbGVfZ29zZXEoc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImRlbHRhX2NvbXAiXV0sIGdvX2RiID0gZ29fZGIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9kYiA9IGxlbmd0aF9kYiwgbWluX3hyZWYgPSA1KQpnb3NlcV9kb3duX2RlbHRhX2NvbXAKYGBgCgojIENpcmNvcwoKSSB0aGluayBpdCB3b3VsZCBiZSBuaWNlIHRvIGhhdmUgdGhlIHd0IG1lYW4gZXhwcmVzc2lvbiB2YWx1ZXMgYXMgYQpiYXNlbGluZQoKYGBge3J9Cm1lYW5zIDwtIG1lYW5fYnlfZmFjdG9yKG5vcm0pW1sibWVkaWFucyJdXQpgYGAKCiMjIENvbGxlY3QgdGhlIFNUUEtzCgpgYGB7cn0Kc3Rwa19vcGVyb25zIDwtIGMoInBrbkEiLCAicGtuQiIsICMjIH4xNWssIHBlcmhhcHMgZW5kaW5nIGEgNyBnZW5lIG9wZXJvbiAoZmhhQSwgZmhhQiwgcHN0UCwgcm9kQSwgcmJwQSwgcGtuQSwgcGtuQikKICAgICAgICAgICAgICAgICAjIyBObyBwa25DCiAgICAgICAgICAgICAgICAgInBrbkQiLCAjIyB+IDEwMzg1MDAsIHBlcmhhcHMgMiBnZW5lIG9wZXJvbiB3aXRoIHBzdFMyCiAgICAgICAgICAgICAgICAgInBrbkUiLCAjIyB+IDIwMDAwMDAsIHBlcmhhcHMgd2l0aCB2YXBCMzQsIHZhcEMzNCwgUnYxNzQyLCBwa25FCiAgICAgICAgICAgICAgICAgInBrbkYiLCAjIyB+IDIwMDAwMDAsIGNsb3NlIHRvIEUsIHBrbkYsIFJ2MTc0NywgUnYxNzQ4CiAgICAgICAgICAgICAgICAgInBrbkciLCAjIyB+IDIwMDAwMDAsIFJ2MDQxMmMsIGhsbkgsIHBrbkcKICAgICAgICAgICAgICAgICAicGtuSCIsICMjIH4gMTQxNTAwMCwgbWF5YmUgOCBnZW5lcywgUnYxMjczYywgUnYxMjcyYywgUnYxMjcxYywgbHByQSwgUnYxMjY5YywgUnYxMjY4YywgZW1iUiwgcGtuSAogICAgICAgICAgICAgICAgICJwa25JIiwgIyMgfiAzMjIyMDAwLCBmZmgsIFJ2MjkxNWMsIHBrbkksIFJ2MjkxM2MsIFJ2MjkxMmMKICAgICAgICAgICAgICAgICAicGtuSiIsICMjIH4gMjM0NTAwMCwgUnYyMDgyLCBSdjIwODMsIFJ2MjA4NCwgUnYyMDg1LCBSdjIwODYsIFJ2MjA4NywgcGtuSgogICAgICAgICAgICAgICAgICJwa25LIiwgIyMgfiAzNDQyNTAwLCBwa25LLCBSdjMwNzljCiAgICAgICAgICAgICAgICAgInBrbkwiLAogICAgICAgICAgICAgICAgICJscHBIIiAjIyB3aGVuIHNlYXJjaGluZyBmb3IgcGtuTSwgbHBwaEgsIFJ2MzU3NywgYXJzQjIgNDAxNTAwMAogICAgICAgICAgICAgICAgICkKbWFwcGVkX3N0cGsgPC0gc2luZ2xlX2dlbmVfbWFwcGluZ1tbImgzN19nZW5lIl1dICVpbiUgc3Rwa19vcGVyb25zCm1hcHBlZF9pZHMgPC0gc2luZ2xlX2dlbmVfbWFwcGluZ1ttYXBwZWRfc3RwaywgXQptYXBwZWRfaWRzCm1hcHBlZF9pZHNbWyJjZGMxNTUxX3RhZyJdXQojIyBPaCBubyBzaGl0IHRoZSByZWFzb24gSSBjb3VsZG4ndCBmaW5kIHRoZW0gYmVmb3JlIHdhcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHBrbkIgYW5kIFBrbkIsIGRhbW5pdC4KIyMgU28gdGhhdCBpcyBhbm5veWluZyBJIGxpa2VseSBkaWQgbm90IG5lZWQgdG8gZG8gdGhlIHNpbGx5IG9ydGhvbG9nIG1hcCBhdCBhbGwuCmBgYAoKTGV0IHVzIGFkZCBhIGNvbHVtbiB0byB0aGUgYW5ub3RhdGlvbnMgbm90aW5nIHRoZSBTVFBLcyBhbmQKcG90ZW50aWFsbHkgaW5jbHVkZSB0aGVtIGluIHRoZSBjaXJjb3MgcGxvdC4KClRoZSBjdXJyZW50IG1hcCBpcyBpbiBvcmRlciBmcm9tIG91dGVyLT5pbm5lcgoKKiArIHN0cmFuZCBnZW5lcyBjb2xvcmVkIGJ5IENPR0Z1bgoqIC0gc3RyYW5kIGdlbmVzCiogV1QgZ2VuZSBleHByZXNzaW9uIG9uIGxvZyBzY2FsZSwgY29sb3Igc2NhbGUgY2hvc2VuIGF1dG9tYXRpY2FsbHkgYXMKICBoZWF0bWFwCiogzpQvV1QgY29tcGFyaXNvbiBvbiBsb2cgc2NhbGUsIGNvbG9yIHNjYWxlIGNob3NlbiBhdXRvbWF0aWNhbGx5IGFzCiAgaGVhdG1hcAoqIGNvbXAvV1QgY29tcGFyaXNvbiwgSWJpZC4KKiDOlC9jb21wIGNvbXBhcmlzb24sIEliaWQuCiogaWRlYWxseSwgdGlsZXMgc2hvd2luZyB0aGUgbG9jYXRpb24gb2YgdGhlIDExIFNUUEtzIGFuZCAxIHJhbmRvCiAgd2hpY2ggbWlnaHQgYWxzbyBiZSBhIFNUUEsuCgpgYGB7cn0KYW5ub3RbWyJjaHJvbW9zb21lIl1dIDwtICJBRTAwMDUxNiIKYW5ub3RbWyJzdHBrIl1dIDwtICJOVUxMIgphbm5vdFttYXBwZWRfaWRzW1siY2RjMTU1MV90YWciXV0sICJzdHBrIl0gPC0gInN0cGsiCnN0cGtfcm93cyA8LSBhbm5vdFttYXBwZWRfaWRzW1siY2RjMTU1MV90YWciXV0sIF0KCmRlbHRhX3d0X2RmIDwtIHRhYmxlc1tbImRhdGEiXV1bWyJkZWx0YV93dCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KY29tcF93dF9kZiA8LSB0YWJsZXNbWyJkYXRhIl1dW1siY29tcF93dCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KZGVsdGFfY29tcF9kZiA8LSB0YWJsZXNbWyJkYXRhIl1dW1siZGVsdGFfY29tcCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KCnBrbmZfY2ZnIDwtIGNpcmNvc19wcmVmaXgoYW5ub3QsIG5hbWU9InBrbmYiLCBjb2dfY29sdW1uID0gIkNPR0Z1biIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfY29sdW1uID0gInN0YXJ0Iiwgc3RvcF9jb2x1bW4gPSAic3RvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyYW5kX2NvbHVtbiA9ICJzdHJhbmQiLCBjaHJfY29sdW1uID0gImNocm9tb3NvbWUiKQpwa25mX2thcnkgPC0gY2lyY29zX2thcnlvdHlwZSgKICBwa25mX2NmZywgZmFzdGEgPSAifi9saWJyYXJpZXMvZ2Vub21lL215Y29iYWN0ZXJpdW1fdHViZXJjdWxvc2lzX2NkYzE1NTEuZmFzdGEiKQpwbHVzX21pbnVzIDwtIGNpcmNvc19wbHVzX21pbnVzKHBrbmZfY2ZnLCB3aWR0aCA9IDAuMDYsIHRoaWNrbmVzcyA9IDQwKQp3dF9leHByc19oZWF0IDwtIGNpcmNvc19oZWF0bWFwKHBrbmZfY2ZnLCBtZWFucywgY29sbmFtZSA9ICJ3dCIsIGJhc2VuYW1lID0gIm1lYW5fd3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGVyID0gcGx1c19taW51cykKZGVsdGFfd3RfaGlzdCA8LSBjaXJjb3NfaGVhdG1hcChwa25mX2NmZywgZGVsdGFfd3RfZGYsIGNvbG5hbWUgPSAiZGVzZXFfbG9nZmMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VuYW1lID0gImRlbHRhX3d0Iiwgb3V0ZXIgPSB3dF9leHByc19oZWF0KQpjb21wX3d0X2hpc3QgPC0gY2lyY29zX2hlYXRtYXAocGtuZl9jZmcsIGNvbXBfd3RfZGYsIGNvbG5hbWUgPSAiZGVzZXFfbG9nZmMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZW5hbWUgPSAiY29tcF93dCIsIG91dGVyID0gZGVsdGFfd3RfaGlzdCkKZGVsdGFfY29tcF9oaXN0IDwtIGNpcmNvc19oZWF0bWFwKHBrbmZfY2ZnLCBkZWx0YV9jb21wX2RmLCBjb2xuYW1lID0gImRlc2VxX2xvZ2ZjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VuYW1lID0gImRlbHRhX2NvbXAiLCBvdXRlciA9IGNvbXBfd3RfaGlzdCkKdGlsZV9jb2xvcnMgPC0gIjAwMDBBQSIKbmFtZXModGlsZV9jb2xvcnMpIDwtIGMoInN0cGsiKQpzdHBrX3RpbGVzIDwtIGNpcmNvc190aWxlKHBrbmZfY2ZnLCBzdHBrX3Jvd3MsIGNvbG5hbWUgPSAic3RwayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gdGlsZV9jb2xvcnMsIHdpZHRoID0gMC4xMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkZGluZyA9IDAsIHRoaWNrbmVzcyA9IDEyNSwgbWFyZ2luID0gMC4wMCwKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlbmFtZSA9ICJzdHBrIiwgb3V0ZXIgPSBkZWx0YV9jb21wX2hpc3QpCmZpbmlzaCA8LSBjaXJjb3Nfc3VmZml4KHBrbmZfY2ZnKQptYWRlIDwtIGNpcmNvc19tYWtlKHBrbmZfY2ZnLCB0YXJnZXQgPSAicGtuZiIpCmBgYAoKT25lIG9mIHRoZSBwcmltYXJ5IHJlYXNvbnMgSSB1c3VhbGx5IGRvIGhpc3RvZ3JhbXMgaW5zdGVhZCBvZgpoZWF0bWFwczogSSBkbyBub3QgcmVhbGx5IHVuZGVyc3RhbmQgaG93IHRvIGxheSBvdXQgdGhlIGNvbG9yIHJhbmdlIHNvCnRoYXQgaXQgaXMgY29uc2lzdGVudCBhY3Jvc3MgZGlmZmVyZW50IHJhbmdlcyBvZiBsb2dGQyB2YWx1ZXMgKEkKc3VwcG9zZSBJIGNvdWxkIGp1c3Qgbm9ybWFsaXplIHRoZW0gdG8gLTE8PXg8PTE/CgpUaGUgZm9sbG93aW5nIGlzIHB1bGxlZCBmcm9tIGEgUHNldWRvbW9uYXMgdGlsaW5nIG9mIHNwZWNpZmljIGdlbmVzIG9mCmludGVyZXN0OyBJIGhhdmUgYSBmZWVsaW5nIHRoYXQgdGhlIHZhcmlvdXMgU1RQS3MgbWF5IHdhbnQgdG8gYmUgYWRkZWQKaW4gYSBzaW1pbGFyIGZhc2hpb24KCgoKYGBge3IsIGV2YWw9RkFMU0V9Cm90aGVyIDwtIGMoImdlbmUxNjUyMDk1IiwgImdlbmUxNjUyMDk3IiwgImdlbmUxNjUyMDk5IiwgImdlbmUxNjUyMTAxIiwKICAgICAgICAgICAiZ2VuZTE2NTIxMDMiLCAiZ2VuZTE2NTIxMDUiLCAiZ2VuZTE2NTIxMDciLCAiZ2VuZTE2NTIxMDkiLAogICAgICAgICAgICJnZW5lMTY1MjExMSIsICJnZW5lMTY1MjExMyIsICJnZW5lMTY1MjExNSIsICJnZW5lMTY1MjExNyIsCiAgICAgICAgICAgImdlbmUxNjUyMTE5IiwgImdlbmUxNjUyMTIxIiwgImdlbmUxNjUyMTIzIiwgImdlbmUxNjUyMTI1IiwKICAgICAgICAgICAiZ2VuZTE2NTIxMjciLCAiZ2VuZTE2NTIxMjkiLCAiZ2VuZTE2NTIxMzEiLCAiZ2VuZTE2NTIxMzMiLAogICAgICAgICAgICJnZW5lMTY1MjEzNSIsICJnZW5lMTY1MjEzNyIsICJnZW5lMTY1MjEzOSIsICJnZW5lMTY1MjE0MSIsCiAgICAgICAgICAgImdlbmUxNjUyMTQzIiwgImdlbmUxNjUyMTQ1IiwgImdlbmUxNjUyMTQ3IiwgImdlbmUxNjUyMTQ5IiwKICAgICAgICAgICAiZ2VuZTE2NTIxNTEiLCAiZ2VuZTE2NTIxNTMiLCAiZ2VuZTE2NTIxNTUiLCAiZ2VuZTE2NTIxNTciLAogICAgICAgICAgICJnZW5lMTY1MjE1OSIsICJnZW5lMTY1MjE2MSIsICJnZW5lMTY1MjE2MyIsICJnZW5lMTY1MjE2NSIpCiMjIGFsc28gQkxVRQpwZWwgPC0gYygiZ2VuZTE2NTQ3ODciLCAiZ2VuZTE2NTQ3ODkiLCAiZ2VuZTE2NTQ3OTMiLAogICAgICAgICAiZ2VuZTE2NTQ3OTUiLCAiZ2VuZTE2NTQ3OTciLCAiZ2VuZTE2NTQ3OTkiKQpleHRyYVtkb3duX29ybiwgImZsYWciXSA8LSAiZG93bl9vcm4iCmV4dHJhW3VwX29ybiwgImZsYWciXSA8LSAidXBfb3JuIgpleHRyYVtlZmZlY3RvcnMsICJmbGFnIl0gPC0gImVmZmVjdG9ycyIKZXh0cmFbb3RoZXIsICJmbGFnIl0gPC0gIm90aGVyIgpleHRyYVtwZWwsICJmbGFnIl0gPC0gInBlbCIKa2VlcF9pZHggPC0gZXh0cmFbWyJmbGFnIl1dICE9ICIiCmV4dHJhIDwtIGV4dHJhW2tlZXBfaWR4LCBdCnN1bW1hcnkoYXMuZmFjdG9yKGV4dHJhJGZsYWcpKQoKCmBgYAo=