1 M. musculus

This will be a very minimal analysis until we get some replicates.

1.1 Annotations

I am using mm38_100.

## My load_biomart_annotations() function defaults to human, so that will be quick.
mm_annot <- load_biomart_annotations(species="mmusculus")
## The biomart annotations file already exists, loading from it.
mm_annot <- mm_annot[["annotation"]]
mm_annot[["txid"]] <- paste0(mm_annot[["ensembl_transcript_id"]], ".", mm_annot[["version"]])
rownames(mm_annot) <- make.names(mm_annot[["ensembl_gene_id"]], unique=TRUE)

tx_gene_map <- mm_annot[, c("txid", "ensembl_gene_id")]

So, I now have a table of mouse annotations.

1.2 Metadata

I am going to write a quick sample sheet in the current working directory called ‘all_samples.xlsx’ and put the names of the count tables in it.

1.3 Create expressionsets

Here I combine the metadata, count data, and annotations.

It is worth noting that the gene IDs from htseq-count probably do not match the annotations retrieved because they are likely exon-based rather than gene based. This is not really a problem, but don’t forget it!

1.4 Hisat2 expressionset

hisat_annot <- mm_annot
rownames(hisat_annot) <- paste0("gene:", rownames(hisat_annot))
mm38_hisat <- create_expt("sample_sheets/all_samples.xlsx",
                          gene_info=hisat_annot)
## Reading the sample metadata.
## Dropped 1 rows from the sample metadata because they were blank.
## The sample definitions comprises: 23 rows(samples) and 24 columns(metadata fields).
## Reading count tables.
## Reading count files with read.table().
## /mnt/sshfs/cbcbsub01/fs/cbcb-lab/nelsayed/scratch/atb/rnaseq/mmusculus_iprgc_2019/preprocessing/iprgc_01/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows.
## preprocessing/iprgc_02/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_03/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_04/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_05/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_06/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_07/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/iprgc_08/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/01_wt_retina/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/02_wt_scn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/03_wt_dlgn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/04_ko_retina/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/05_ko_scn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/06_ko_dlgn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/07_het1_retina/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/08_het2_retina/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/09_het3_retina/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/10_het1_scn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/11_het2_scn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/12_het3_scn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/13_het1_dlgn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/14_het2_dlgn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## preprocessing/202009/15_het3_dlgn/outputs/hisat2_mm38_100/r1_ca.count_mm38_100_sno_gene_ID.count.xz contains 25765 rows and merges to 25765 rows.
## Finished reading count data.
## Matched 25419 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 25760 rows and 23 columns.
plot_libsize(mm38_hisat)$plot

mm38_first <- normalize_expt(mm38_hisat, filter=TRUE, convert="cpm", norm="quant", transform="log2")
## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 11159 low-count genes (14601 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 20 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
pp(file="pre_pca.png", image=plot_pca(mm38_first)$plot)
## Writing the image to: pre_pca.png and calling dev.off().

mm38_norm <- normalize_expt(mm38_hisat, filter=TRUE, convert="cpm", batch="svaseq")
## This function will replace the expt$expressionset slot with:
## svaseq(cpm(cbcb(data)))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Step 1: performing count filter with option: cbcb
## Removing 11159 low-count genes (14601 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: not transforming the data.
## Step 5: doing batch correction with svaseq.
## Using the current state of normalization.
## Passing the data to all_adjusters using the svaseq estimate type.
## batch_counts: Before batch/surrogate estimation, 309316 entries are x>1: 92%.
## batch_counts: Before batch/surrogate estimation, 2857 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 23650 entries are 0<x<1: 7%.
## The be method chose 2 surrogate variables.
## Attempting svaseq estimation with 2 surrogates.
## There are 2108 (1%) elements which are < 0 after batch correction.
## Setting low elements to zero.
mm38_norm <- normalize_expt(mm38_norm, transform="log2")
## This function will replace the expt$expressionset slot with:
## log2(data)
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Filter is false, this should likely be set to something, good
##  choices include cbcb, kofa, pofa (anything but FALSE).  If you want this to
##  stay FALSE, keep in mind that if other normalizations are performed, then the
##  resulting libsizes are likely to be strange (potentially negative!)
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: not doing count filtering.
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: transforming the data with log2.
## transform_counts: Found 2108 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
pp(file="post_pca.png", image=plot_pca(mm38_norm)$plot)
## Writing the image to: post_pca.png and calling dev.off().

mm38_salmon <- create_expt("sample_sheets/all_samples.xlsx", tx_gene_map=tx_gene_map,
                              gene_info=mm_annot, file_column="salmonfile")
## Reading the sample metadata.
## Dropped 1 rows from the sample metadata because they were blank.
## The sample definitions comprises: 23 rows(samples) and 24 columns(metadata fields).
## Reading count tables.
## Using the transcript to gene mapping.
## Reading salmon data with tximport.
## Finished reading count data.
## Matched 6431 annotations and counts.
## Bringing together the count matrix and gene information.
## The mapped IDs are not the rownames of your gene information, changing them now.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 6431 rows and 23 columns.
mmtx_annot <- mm_annot
rownames(mmtx_annot) <- mm_annot[["txid"]]
mm38_saltx <- sm(create_expt("sample_sheets/all_samples.xlsx",
                             gene_info=mmtx_annot, file_column="salmonfile"))

1.5 Query expressionsets

In this block I will calculate all the diagnostic plots, but not show them. I will show them next with a little annotation.

I will leave the output for the first of each invocation and silence it for the second.

1.5.1 Initial salmon plots

mm38_plots_sa <- sm(graph_metrics(mm38_salmon))
mm38_norm_sa <- normalize_expt(mm38_salmon, norm="quant", convert="cpm",
                               transform="log2", filter=TRUE)
## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 2223 low-count genes (4208 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 11131 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
mm38n_plots_sa <- graph_metrics(mm38_norm_sa)
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Graphing a boxplot.
## Graphing a correlation heatmap.
## Graphing a standard median correlation.
## Performing correlation.
## Graphing a distance heatmap.
## Graphing a standard median distance.
## Performing distance.
## Graphing a PCA plot.
## Graphing a T-SNE plot.
## Plotting a density plot.
## Plotting a CV plot.
## Naively calculating coefficient of variation/dispersion with respect to condition.
## Finished calculating dispersion estimates.
## Plotting the representation of the top-n genes.
## Plotting the expression of the top-n PC loaded genes.
## Printing a color to condition legend.
mm38_plots_sa$legend

mm38_plots_sa$libsize

mm38_plots_sa$nonzero

mm38n_plots_sa$density

mm38n_plots_sa$pc_plot

1.5.2 Initial hisat2 plots

mm38_plots_hi <- sm(graph_metrics(mm38_hisat))
mm38_norm_hi <- normalize_expt(mm38_hisat, norm="quant", convert="cpm",
                               transform="log2", filter=TRUE)
## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 11159 low-count genes (14601 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 20 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
mm38n_plots_hi <- sm(graph_metrics(mm38_norm_hi))
mm38_normbatch_hi <- normalize_expt(mm38_hisat, filter=TRUE)
## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 11159 low-count genes (14601 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
mm38_normbatch_hi <- normalize_expt(mm38_normbatch_hi, norm="quant", batch="svaseq")
## This function will replace the expt$expressionset slot with:
## svaseq(quant(data))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Filter is false, this should likely be set to something, good
##  choices include cbcb, kofa, pofa (anything but FALSE).  If you want this to
##  stay FALSE, keep in mind that if other normalizations are performed, then the
##  resulting libsizes are likely to be strange (potentially negative!)
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Warning in normalize_expt(mm38_normbatch_hi, norm = "quant", batch = "svaseq"):
## Quantile normalization and sva do not always play well together.
## Step 1: not doing count filtering.
## Step 2: normalizing the data with quant.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: doing batch correction with svaseq.
## Using the current state of normalization.
## Passing the data to all_adjusters using the svaseq estimate type.
## batch_counts: Before batch/surrogate estimation, 332778 entries are x>1: 99%.
## batch_counts: Before batch/surrogate estimation, 20 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 3025 entries are 0<x<1: 1%.
## The be method chose 2 surrogate variables.
## Attempting svaseq estimation with 2 surrogates.
## There are 517 (0%) elements which are < 0 after batch correction.
## Setting low elements to zero.
mm38_normbatch_hi <- normalize_expt(mm38_normbatch_hi, transform="log2")
## This function will replace the expt$expressionset slot with:
## log2(data)
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Filter is false, this should likely be set to something, good
##  choices include cbcb, kofa, pofa (anything but FALSE).  If you want this to
##  stay FALSE, keep in mind that if other normalizations are performed, then the
##  resulting libsizes are likely to be strange (potentially negative!)
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: not doing count filtering.
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: transforming the data with log2.
## transform_counts: Found 517 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
mm38_plots_hi$libsize

mm38_plots_hi$nonzero

mm38n_plots_hi$density

mm38n_plots_hi$pc_plot

1.6 Do a simple DE

The only interesting DE I see in this is to compare the retinas to the dlgns. I can treat them as replicates and compare.

These differential expression analyses are EXPLICITLY NOT what you care about. However, they are useful for two purposes:

  1. Seeing that the three tissue types are indeed different.
  2. Setting up the table of results with appropriate rows/columns of (rows)genes and (columns) annotations. We will therefore add to these tables the results of the expression analyses that you actually do care about.

When we receive full replicate sets, this cheater method of encapsulating the data will not longer be required.

1.6.1 With salmon

mm_sa <- set_expt_conditions(mm38_salmon, fact="celltype")
mm_norm_sa <- sm(normalize_expt(mm_sa, convert="rpkm", transform="log2", column="cds_length"))
plot_pca(mm_norm_sa)$plot

mm_de_sa <- all_pairwise(mm_sa, model_batch=FALSE)

1.6.2 With hisat2

normal_keepers <- list(
  "wt_dlgnret" = c("wt_dlgn", "wt_retina"),
  "wt_scnret" = c("wt_scn", "wt_retina"),
  "wt_dlgnscn" = c("wt_dlgn", "wt_scn"),
  "het_dlgnret" = c("het_dlgn", "het_retina"),
  "het_scnret" = c("het_scn", "het_retina"),
  "het_dlgnscn" = c("het_dlgn", "het_scn"),
  "ko_dlgnret" = c("ko_dlgn", "ko_retina"),
  "ko_scnret" = c("ko_scn", "ko_retina"),
  "ko_dlgnscn" = c("ko_dlgn", "ko_scn"),
  "normret" = c("het_retina", "wt_retina"),
  "koret" = c("ko_retina", "wt_retina"),
  "normscn" = c("het_scn", "wt_scn"),
  "koscn" = c("ko_scn", "wt_scn"),
  "normdlgn" = c("het_dlgn", "wt_dlgn"),
  "kodlgn" = c("ko_dlgn", "wt_dlgn")
  )

all_keepers <- list(
  "wt_dlgnret" = c("wt_dlgn", "wt_retina"),
  "wt_scnret" = c("wt_scn", "wt_retina"),
  "wt_dlgnscn" = c("wt_dlgn", "wt_scn"),
  "het_dlgnret" = c("het_dlgn", "het_retina"),
  "het_scnret" = c("het_scn", "het_retina"),
  "het_dlgnscn" = c("het_dlgn", "het_scn"),
  "ko_dlgnret" = c("ko_dlgn", "ko_retina"),
  "ko_scnret" = c("ko_scn", "ko_retina"),
  "ko_dlgnscn" = c("ko_dlgn", "ko_scn"),
  "normret" = c("het_retina", "wt_retina"),
  "koret" = c("ko_retina", "wt_retina"),
  "normscn" = c("het_scn", "wt_scn"),
  "koscn" = c("ko_scn", "wt_scn"),
  "normdlgn" = c("het_dlgn", "wt_dlgn"),
  "kodlgn" = c("ko_dlgn", "wt_dlgn"),
  "normdlgn_vs_normret" = c("normdlgn", "normret"),
  "normscn_vs_normret" = c("normscn", "normret"),
  "kodlgn_vs_koret" = c("kodlgn", "koret"),
  "koscn_vs_koret" = c("koscn", "koret"),
  "koscn_vs_kodlgn" = c("koscn", "kodlgn"),
  "koret_vs_normret" = c("ko_retina", "het_retina"),
  "koscn_vs_normscn" = c("ko_scn", "het_scn"),
  "kodlgn_vs_normdlgn" = c("ko_dlgn", "het_dlgn"),
  "normko_retdlgn" = c("normdlgn_vs_normret", "kodlgn_vs_koret"),
  "normko_retscn" = c("normscn_vs_normret", "koscn_vs_koret"))

extra_contrasts <- "normdlgn_vs_normret = (het_dlgn-wt_dlgn)-(het_retina-wt_retina),
           normscn_vs_normret = (het_scn-wt_scn)-(het_retina-wt_retina),
           kodlgn_vs_koret = (ko_dlgn-wt_dlgn)-(ko_retina-wt_retina),
           koscn_vs_koret = (ko_scn-wt_scn)-(ko_retina-wt_retina),
           koscn_vs_kodlgn = (ko_scn-wt_scn)-(ko_dlgn-wt_dlgn),
           normko_vs_retdlgn = ((het_dlgn-wt_dlgn)-(het_retina-wt_retina)) - ((ko_dlgn-wt_dlgn)-(ko_retina-wt_retina)),
           normko_vs_retscn = ((het_scn-wt_scn)-(het_retina-wt_retina)) - ((ko_scn-wt_scn)-(ko_retina-wt_retina))"

mm_filt <- normalize_expt(mm38_hisat, filter=TRUE)
## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 11159 low-count genes (14601 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
## mm_limma <- sm(limma_pairwise(mm_filt, model_batch="svaseq", extra_contrasts=extras))
mm_deseq <- deseq_pairwise(mm_filt, model_batch="svaseq")
## Hey you, use deseq2 pairwise.
## Starting DESeq2 pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq. If they freak out, check the state of the count table and ensure that it is in integer counts.
## Extracting surrogate estimates from svaseq and adding them to the model.
## batch_counts: Before batch/surrogate estimation, 331257 entries are x>1: 99%.
## batch_counts: Before batch/surrogate estimation, 2857 entries are x==0: 1%.
## The be method chose 2 surrogate variables.
## Attempting svaseq estimation with 2 surrogates.
## Choosing the non-intercept containing model.
## DESeq2 step 1/5: Including a matrix of batch estimates in the deseq model.
## converting counts to integer mode
## DESeq2 step 2/5: Estimate size factors.
## DESeq2 step 3/5: Estimate dispersions.
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## Using a parametric fitting seems to have worked.
## DESeq2 step 4/5: nbinomWaldTest.
## mm_edger <- sm(edger_pairwise(mm_filt, model_batch="svaseq", extra_contrasts=extras))
## mm_basic <- sm(basic_pairwise(mm_filt, model_batch="svaseq", extra_contrasts=extras))
## mm_ebseq <- ebseq_pairwise(mm_filt, model_batch="svaseq", extra_contrasts=extras)

mm_write <- write_expt(mm_filt, excel="excel/raw_data_and_metrics_20201030.xlsx")
## Writing the first sheet, containing a legend and some summary data.
## Writing the raw reads.
## Graphing the raw reads.
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## Warning in doTryCatch(return(expr), name, parentenv, handler): display list
## redraw incomplete

## Warning in doTryCatch(return(expr), name, parentenv, handler): display list
## redraw incomplete
## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Dividing work into 100 chunks...
## Error in serialize(data, node$con, xdr = FALSE) : 
##   error writing to connection
## A couple of common errors:
## An error like 'vtv downdated' may be because there are too many 0s, filter the data and rerun.
## An error like 'number of levels of each grouping factor must be < number of observations' means
## that the factor used is not appropriate for the analysis - it really only works for factors
## which are shared among multiple samples.
## Retrying with only condition in the model.
## Loading required package: Matrix
## 
## Total:82 s
## Placing factor: condition at the beginning of the model.
## Writing the normalized reads.
## Graphing the normalized reads.
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## Warning in doTryCatch(return(expr), name, parentenv, handler): display list
## redraw incomplete

## Warning in doTryCatch(return(expr), name, parentenv, handler): display list
## redraw incomplete
## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Dividing work into 100 chunks...
## Error in serialize(data, node$con, xdr = FALSE) : 
##   error writing to connection
## A couple of common errors:
## An error like 'vtv downdated' may be because there are too many 0s, filter the data and rerun.
## An error like 'number of levels of each grouping factor must be < number of observations' means
## that the factor used is not appropriate for the analysis - it really only works for factors
## which are shared among multiple samples.
## Retrying with only condition in the model.
## 
## Total:91 s
## Placing factor: condition at the beginning of the model.
## Writing the median reads by factor.
mm_de_normal <- all_pairwise(mm_filt, model_batch="svaseq", parallel=FALSE, do_ebseq=FALSE)
## batch_counts: Before batch/surrogate estimation, 331257 entries are x>1: 99%.
## batch_counts: Before batch/surrogate estimation, 2857 entries are x==0: 1%.
## The be method chose 2 surrogate variables.
## Attempting svaseq estimation with 2 surrogates.
## Plotting a PCA before surrogate/batch inclusion.
## Not putting labels on the PC plot.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## This function will replace the expt$expressionset slot with:
## log2(svaseq(cpm(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Step 1: performing count filter with option: cbcb
## Removing 0 low-count genes (14601 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 2857 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with svaseq.
## Using the current state of normalization.
## Passing the data to all_adjusters using the svaseq estimate type.
## batch_counts: Before batch/surrogate estimation, 309316 entries are x>1: 92%.
## batch_counts: Before batch/surrogate estimation, 2857 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 23650 entries are 0<x<1: 7%.
## The be method chose 2 surrogate variables.
## Attempting svaseq estimation with 2 surrogates.
## There are 2108 (1%) elements which are < 0 after batch correction.
## Setting low elements to zero.
## Not putting labels on the PC plot.
## Starting basic_pairwise().
## Starting basic pairwise comparison.
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Basic step 1/3: Creating mean and variance tables.
## Basic step 2/3: Performing 45 comparisons.
## Basic step 3/3: Creating faux DE Tables.
## Basic: Returning tables.
## Starting deseq_pairwise().
## Starting DESeq2 pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq. If they freak out, check the state of the count table and ensure that it is in integer counts.
## Including batch estimates from sva/ruv/pca in the model.
## Choosing the non-intercept containing model.
## DESeq2 step 1/5: Including a matrix of batch estimates in the deseq model.
## converting counts to integer mode
## DESeq2 step 2/5: Estimate size factors.
## DESeq2 step 3/5: Estimate dispersions.
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## Using a parametric fitting seems to have worked.
## DESeq2 step 4/5: nbinomWaldTest.
## Starting edger_pairwise().
## Starting edgeR pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq. If they freak out, check the state of the count table and ensure that it is in integer counts.
## Including batch estimates from sva/ruv/pca in the model.
## Choosing the non-intercept containing model.
## EdgeR step 1/9: Importing and normalizing data.
## EdgeR step 2/9: Estimating the common dispersion.
## EdgeR step 3/9: Estimating dispersion across genes.
## EdgeR step 4/9: Estimating GLM Common dispersion.
## EdgeR step 5/9: Estimating GLM Trended dispersion.
## EdgeR step 6/9: Estimating GLM Tagged dispersion.
## EdgeR step 7/9: Running glmFit, switch to glmQLFit by changing the argument 'edger_test'.
## EdgeR step 8/9: Making pairwise contrasts.
## Starting limma_pairwise().
## Starting limma pairwise comparison.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Limma step 1/6: choosing model.
## Including batch estimates from sva/ruv/pca in the model.
## Choosing the non-intercept containing model.
## Limma step 2/6: running limma::voom(), switch with the argument 'which_voom'.
## Using normalize.method=quantile for voom.
## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## Limma step 5/6: Running eBayes with robust=FALSE and trend=FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/36: Creating table: het_retina_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 2/36: Creating table: het_scn_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 3/36: Creating table: ko_dlgn_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 4/36: Creating table: ko_retina_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 5/36: Creating table: ko_scn_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 6/36: Creating table: wt_dlgn_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 7/36: Creating table: wt_retina_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 8/36: Creating table: wt_scn_vs_het_dlgn.  Adjust=BH
## Limma step 6/6: 9/36: Creating table: het_scn_vs_het_retina.  Adjust=BH
## Limma step 6/6: 10/36: Creating table: ko_dlgn_vs_het_retina.  Adjust=BH
## Limma step 6/6: 11/36: Creating table: ko_retina_vs_het_retina.  Adjust=BH
## Limma step 6/6: 12/36: Creating table: ko_scn_vs_het_retina.  Adjust=BH
## Limma step 6/6: 13/36: Creating table: wt_dlgn_vs_het_retina.  Adjust=BH
## Limma step 6/6: 14/36: Creating table: wt_retina_vs_het_retina.  Adjust=BH
## Limma step 6/6: 15/36: Creating table: wt_scn_vs_het_retina.  Adjust=BH
## Limma step 6/6: 16/36: Creating table: ko_dlgn_vs_het_scn.  Adjust=BH
## Limma step 6/6: 17/36: Creating table: ko_retina_vs_het_scn.  Adjust=BH
## Limma step 6/6: 18/36: Creating table: ko_scn_vs_het_scn.  Adjust=BH
## Limma step 6/6: 19/36: Creating table: wt_dlgn_vs_het_scn.  Adjust=BH
## Limma step 6/6: 20/36: Creating table: wt_retina_vs_het_scn.  Adjust=BH
## Limma step 6/6: 21/36: Creating table: wt_scn_vs_het_scn.  Adjust=BH
## Limma step 6/6: 22/36: Creating table: ko_retina_vs_ko_dlgn.  Adjust=BH
## Limma step 6/6: 23/36: Creating table: ko_scn_vs_ko_dlgn.  Adjust=BH
## Limma step 6/6: 24/36: Creating table: wt_dlgn_vs_ko_dlgn.  Adjust=BH
## Limma step 6/6: 25/36: Creating table: wt_retina_vs_ko_dlgn.  Adjust=BH
## Limma step 6/6: 26/36: Creating table: wt_scn_vs_ko_dlgn.  Adjust=BH
## Limma step 6/6: 27/36: Creating table: ko_scn_vs_ko_retina.  Adjust=BH
## Limma step 6/6: 28/36: Creating table: wt_dlgn_vs_ko_retina.  Adjust=BH
## Limma step 6/6: 29/36: Creating table: wt_retina_vs_ko_retina.  Adjust=BH
## Limma step 6/6: 30/36: Creating table: wt_scn_vs_ko_retina.  Adjust=BH
## Limma step 6/6: 31/36: Creating table: wt_dlgn_vs_ko_scn.  Adjust=BH
## Limma step 6/6: 32/36: Creating table: wt_retina_vs_ko_scn.  Adjust=BH
## Limma step 6/6: 33/36: Creating table: wt_scn_vs_ko_scn.  Adjust=BH
## Limma step 6/6: 34/36: Creating table: wt_retina_vs_wt_dlgn.  Adjust=BH
## Limma step 6/6: 35/36: Creating table: wt_scn_vs_wt_dlgn.  Adjust=BH
## Limma step 6/6: 36/36: Creating table: wt_scn_vs_wt_retina.  Adjust=BH
## Limma step 6/6: 1/9: Creating table: het_dlgn.  Adjust=BH
## Limma step 6/6: 2/9: Creating table: het_retina.  Adjust=BH
## Limma step 6/6: 3/9: Creating table: het_scn.  Adjust=BH
## Limma step 6/6: 4/9: Creating table: ko_dlgn.  Adjust=BH
## Limma step 6/6: 5/9: Creating table: ko_retina.  Adjust=BH
## Limma step 6/6: 6/9: Creating table: ko_scn.  Adjust=BH
## Limma step 6/6: 7/9: Creating table: wt_dlgn.  Adjust=BH
## Limma step 6/6: 8/9: Creating table: wt_retina.  Adjust=BH
## Limma step 6/6: 9/9: Creating table: wt_scn.  Adjust=BH
## Comparing analyses.
mm_de_normal_tables <- combine_de_tables(mm_de_normal,
                                         excel="excel/only_pairwise_de_20201030.xlsx",
                                         keepers=normal_keepers)
## Deleting the file excel/only_pairwise_de_20201030.xlsx before writing the tables.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/15: wt_dlgnret which is: wt_dlgn/wt_retina.
## Found inverse table with wt_retina_vs_wt_dlgn
## The ebseq table is null.
## Working on 2/15: wt_scnret which is: wt_scn/wt_retina.
## Found table with wt_scn_vs_wt_retina
## The ebseq table is null.
## Working on 3/15: wt_dlgnscn which is: wt_dlgn/wt_scn.
## Found inverse table with wt_scn_vs_wt_dlgn
## The ebseq table is null.
## Working on 4/15: het_dlgnret which is: het_dlgn/het_retina.
## Found inverse table with het_retina_vs_het_dlgn
## The ebseq table is null.
## Working on 5/15: het_scnret which is: het_scn/het_retina.
## Found table with het_scn_vs_het_retina
## The ebseq table is null.
## Working on 6/15: het_dlgnscn which is: het_dlgn/het_scn.
## Found inverse table with het_scn_vs_het_dlgn
## The ebseq table is null.
## Working on 7/15: ko_dlgnret which is: ko_dlgn/ko_retina.
## Found inverse table with ko_retina_vs_ko_dlgn
## The ebseq table is null.
## Working on 8/15: ko_scnret which is: ko_scn/ko_retina.
## Found table with ko_scn_vs_ko_retina
## The ebseq table is null.
## Working on 9/15: ko_dlgnscn which is: ko_dlgn/ko_scn.
## Found inverse table with ko_scn_vs_ko_dlgn
## The ebseq table is null.
## Working on 10/15: normret which is: het_retina/wt_retina.
## Found inverse table with wt_retina_vs_het_retina
## The ebseq table is null.
## Working on 11/15: koret which is: ko_retina/wt_retina.
## Found inverse table with wt_retina_vs_ko_retina
## The ebseq table is null.
## Working on 12/15: normscn which is: het_scn/wt_scn.
## Found inverse table with wt_scn_vs_het_scn
## The ebseq table is null.
## Working on 13/15: koscn which is: ko_scn/wt_scn.
## Found inverse table with wt_scn_vs_ko_scn
## The ebseq table is null.
## Working on 14/15: normdlgn which is: het_dlgn/wt_dlgn.
## Found inverse table with wt_dlgn_vs_het_dlgn
## The ebseq table is null.
## Working on 15/15: kodlgn which is: ko_dlgn/wt_dlgn.
## Found inverse table with wt_dlgn_vs_ko_dlgn
## The ebseq table is null.
## Adding venn plots for wt_dlgnret.
## Limma expression coefficients for wt_dlgnret; R^2: 0.748; equation: y = 0.834x + 0.769
## Deseq expression coefficients for wt_dlgnret; R^2: 0.75; equation: y = 0.833x + 1.47
## Edger expression coefficients for wt_dlgnret; R^2: 0.751; equation: y = 0.835x + 1.85
## Adding venn plots for wt_scnret.
## Limma expression coefficients for wt_scnret; R^2: 0.709; equation: y = 0.802x + 0.844
## Deseq expression coefficients for wt_scnret; R^2: 0.719; equation: y = 0.831x + 1.44
## Edger expression coefficients for wt_scnret; R^2: 0.719; equation: y = 0.831x + 1.86
## Adding venn plots for wt_dlgnscn.
## Limma expression coefficients for wt_dlgnscn; R^2: 0.897; equation: y = 0.905x + 0.445
## Deseq expression coefficients for wt_dlgnscn; R^2: 0.898; equation: y = 0.938x + 0.539
## Edger expression coefficients for wt_dlgnscn; R^2: 0.898; equation: y = 0.939x + 0.573
## Adding venn plots for het_dlgnret.
## Limma expression coefficients for het_dlgnret; R^2: 0.755; equation: y = 0.844x + 0.74
## Deseq expression coefficients for het_dlgnret; R^2: 0.752; equation: y = 0.851x + 1.34
## Edger expression coefficients for het_dlgnret; R^2: 0.752; equation: y = 0.852x + 1.42
## Adding venn plots for het_scnret.
## Limma expression coefficients for het_scnret; R^2: 0.73; equation: y = 0.803x + 0.859
## Deseq expression coefficients for het_scnret; R^2: 0.737; equation: y = 0.814x + 1.65
## Edger expression coefficients for het_scnret; R^2: 0.738; equation: y = 0.816x + 1.77
## Adding venn plots for het_dlgnscn.
## Limma expression coefficients for het_dlgnscn; R^2: 0.914; equation: y = 0.92x + 0.37
## Deseq expression coefficients for het_dlgnscn; R^2: 0.91; equation: y = 0.941x + 0.57
## Edger expression coefficients for het_dlgnscn; R^2: 0.91; equation: y = 0.942x + 0.552
## Adding venn plots for ko_dlgnret.
## Limma expression coefficients for ko_dlgnret; R^2: 0.726; equation: y = 0.832x + 0.794
## Deseq expression coefficients for ko_dlgnret; R^2: 0.707; equation: y = 0.816x + 1.64
## Edger expression coefficients for ko_dlgnret; R^2: 0.708; equation: y = 0.82x + 1.9
## Adding venn plots for ko_scnret.
## Limma expression coefficients for ko_scnret; R^2: 0.748; equation: y = 0.832x + 0.729
## Deseq expression coefficients for ko_scnret; R^2: 0.729; equation: y = 0.833x + 1.48
## Edger expression coefficients for ko_scnret; R^2: 0.729; equation: y = 0.835x + 1.73
## Adding venn plots for ko_dlgnscn.
## Limma expression coefficients for ko_dlgnscn; R^2: 0.925; equation: y = 0.956x + 0.21
## Deseq expression coefficients for ko_dlgnscn; R^2: 0.914; equation: y = 0.965x + 0.342
## Edger expression coefficients for ko_dlgnscn; R^2: 0.915; equation: y = 0.964x + 0.355
## Adding venn plots for normret.
## Limma expression coefficients for normret; R^2: 0.974; equation: y = 0.997x + 0.0231
## Deseq expression coefficients for normret; R^2: 0.975; equation: y = 0.971x + 0.304
## Edger expression coefficients for normret; R^2: 0.975; equation: y = 0.971x + 0.354
## Adding venn plots for koret.
## Limma expression coefficients for koret; R^2: 0.952; equation: y = 0.98x + 0.0965
## Deseq expression coefficients for koret; R^2: 0.954; equation: y = 0.941x + 0.573
## Edger expression coefficients for koret; R^2: 0.954; equation: y = 0.941x + 0.69
## Adding venn plots for normscn.
## Limma expression coefficients for normscn; R^2: 0.975; equation: y = 1x - 0.0313
## Deseq expression coefficients for normscn; R^2: 0.974; equation: y = 1x - 0.05
## Edger expression coefficients for normscn; R^2: 0.974; equation: y = 1x - 0.0377
## Adding venn plots for koscn.
## Limma expression coefficients for koscn; R^2: 0.966; equation: y = 0.978x + 0.0697
## Deseq expression coefficients for koscn; R^2: 0.967; equation: y = 0.956x + 0.362
## Edger expression coefficients for koscn; R^2: 0.967; equation: y = 0.957x + 0.419
## Adding venn plots for normdlgn.
## Limma expression coefficients for normdlgn; R^2: 0.966; equation: y = 0.997x + 0.0135
## Deseq expression coefficients for normdlgn; R^2: 0.967; equation: y = 0.988x + 0.152
## Edger expression coefficients for normdlgn; R^2: 0.967; equation: y = 0.988x + 0.123
## Adding venn plots for kodlgn.
## Limma expression coefficients for kodlgn; R^2: 0.97; equation: y = 1x - 0.0142
## Deseq expression coefficients for kodlgn; R^2: 0.972; equation: y = 0.968x + 0.329
## Edger expression coefficients for kodlgn; R^2: 0.972; equation: y = 0.968x + 0.313
## Writing summary information, compare_plot is: TRUE.
## Performing save of excel/only_pairwise_de_20201030.xlsx.
mm_de_normal_sig <- extract_significant_genes(mm_de_normal_tables,
                                              excel="excel/only_pairwise_sig_20201030.xlsx")
## Writing a legend of columns.
## Did not find the ebseq_logfc, skipping ebseq.
## Printing significant genes to the file: excel/only_pairwise_sig_20201030.xlsx
## 1/15: Creating significant table up_limma_wt_dlgnret
## 2/15: Creating significant table up_limma_wt_scnret
## 3/15: Creating significant table up_limma_wt_dlgnscn
## 4/15: Creating significant table up_limma_het_dlgnret
## 5/15: Creating significant table up_limma_het_scnret
## 6/15: Creating significant table up_limma_het_dlgnscn
## 7/15: Creating significant table up_limma_ko_dlgnret
## 8/15: Creating significant table up_limma_ko_scnret
## 9/15: Creating significant table up_limma_ko_dlgnscn
## The up table normret is empty.
## The down table normret is empty.
## The up table koret is empty.
## The down table koret is empty.
## The up table normscn is empty.
## The down table normscn is empty.
## The up table koscn is empty.
## The down table koscn is empty.
## The up table normdlgn is empty.
## The up table kodlgn is empty.
## Printing significant genes to the file: excel/only_pairwise_sig_20201030.xlsx
## 1/15: Creating significant table up_edger_wt_dlgnret
## 2/15: Creating significant table up_edger_wt_scnret
## 3/15: Creating significant table up_edger_wt_dlgnscn
## 4/15: Creating significant table up_edger_het_dlgnret
## 5/15: Creating significant table up_edger_het_scnret
## 6/15: Creating significant table up_edger_het_dlgnscn
## 7/15: Creating significant table up_edger_ko_dlgnret
## 8/15: Creating significant table up_edger_ko_scnret
## 9/15: Creating significant table up_edger_ko_dlgnscn
## 10/15: Creating significant table up_edger_normret
## The down table normret is empty.
## 11/15: Creating significant table up_edger_koret
## The up table normscn is empty.
## The down table normscn is empty.
## 13/15: Creating significant table up_edger_koscn
## The down table koscn is empty.
## The up table normdlgn is empty.
## 15/15: Creating significant table up_edger_kodlgn
## Printing significant genes to the file: excel/only_pairwise_sig_20201030.xlsx
## 1/15: Creating significant table up_deseq_wt_dlgnret
## 2/15: Creating significant table up_deseq_wt_scnret
## 3/15: Creating significant table up_deseq_wt_dlgnscn
## 4/15: Creating significant table up_deseq_het_dlgnret
## 5/15: Creating significant table up_deseq_het_scnret
## 6/15: Creating significant table up_deseq_het_dlgnscn
## 7/15: Creating significant table up_deseq_ko_dlgnret
## 8/15: Creating significant table up_deseq_ko_scnret
## 9/15: Creating significant table up_deseq_ko_dlgnscn
## 10/15: Creating significant table up_deseq_normret
## The down table normret is empty.
## 11/15: Creating significant table up_deseq_koret
## The up table normscn is empty.
## The down table normscn is empty.
## 13/15: Creating significant table up_deseq_koscn
## The down table koscn is empty.
## 14/15: Creating significant table up_deseq_normdlgn
## 15/15: Creating significant table up_deseq_kodlgn
## Printing significant genes to the file: excel/only_pairwise_sig_20201030.xlsx
## The up table wt_dlgnret is empty.
## The down table wt_dlgnret is empty.
## The up table wt_scnret is empty.
## The down table wt_scnret is empty.
## The up table wt_dlgnscn is empty.
## The down table wt_dlgnscn is empty.
## 4/15: Creating significant table up_basic_het_dlgnret
## 5/15: Creating significant table up_basic_het_scnret
## 6/15: Creating significant table up_basic_het_dlgnscn
## The up table ko_dlgnret is empty.
## The down table ko_dlgnret is empty.
## The up table ko_scnret is empty.
## The down table ko_scnret is empty.
## The up table ko_dlgnscn is empty.
## The down table ko_dlgnscn is empty.
## The up table normret is empty.
## The down table normret is empty.
## The up table koret is empty.
## The down table koret is empty.
## The up table normscn is empty.
## The down table normscn is empty.
## The up table koscn is empty.
## The down table koscn is empty.
## The up table normdlgn is empty.
## The down table normdlgn is empty.
## The up table kodlgn is empty.
## The down table kodlgn is empty.
## Adding significance bar plots.
vol1 <- mm_de_normal_tables[["plots"]][["het_dlgnret"]][["deseq_vol_plots"]][["plot"]]
annot1 <- mm_de_normal_tables[["data"]][["het_dlgnret"]][["description"]]
vol1[["data"]][["label"]] <- annot1
vol1_ggplotly <- ggplt(gg=vol1, filename="plots/volcano_dlgn_vs_retina.html")
vol2 <- mm_de_normal_tables[["plots"]][["het_scnret"]][["deseq_vol_plots"]][["plot"]]
annot2 <- mm_de_normal_tables[["data"]][["het_scnret"]][["description"]]
vol2[["data"]][["label"]] <- annot2
vol2_ggplotly <- ggplt(gg=vol2, filename="volcano_scn_vs_retina.html")
vol3 <- mm_de_normal_tables[["plots"]][["het_dlgnscn"]][["deseq_vol_plots"]][["plot"]]
annot3 <- mm_de_normal_tables[["data"]][["het_dlgnscn"]][["description"]]
vol3[["data"]][["label"]] <- annot3
vol3_ggplotly <- ggplt(gg=vol3, filename="volcano_dlgn_vs_scn.html")
mm_de_hi <- sm(all_pairwise(mm_filt, model_batch="svaseq", parallel=FALSE, extra_contrasts=extras))
## Error in basic_pairwise(...) : object 'extras' not found

## Error in make_pairwise_contrasts(model_data, conditions, extra_contrasts = extra_contrasts,  : 
##   object 'extras' not found
## Error in make_pairwise_contrasts(model_data, conditions, extra_contrasts = extra_contrasts,  : 
##   object 'extras' not found

## Error in make_pairwise_contrasts(model = chosen_model, conditions = conditions,  : 
##   object 'extras' not found
## Error in basic_pairwise(...) : object 'extras' not found

## Error in make_pairwise_contrasts(model_data, conditions, extra_contrasts = extra_contrasts,  : 
##   object 'extras' not found
## Error in make_pairwise_contrasts(model_data, conditions, extra_contrasts = extra_contrasts,  : 
##   object 'extras' not found
## Error in make_pairwise_contrasts(model = chosen_model, conditions = conditions,  : 
##   object 'extras' not found
## Error in correlate_de_tables(results, annot_df = annot_df, extra_contrasts = extra_contrasts): object 'extras' not found

mm_de_tables <- sm(combine_de_tables(mm_de_hi, excel="excel/testing_20201030.xlsx", keepers=keepers))
## Error in combine_de_tables(mm_de_hi, excel = "excel/testing_20201030.xlsx", : object 'mm_de_hi' not found
mm_de_sig <- sm(extract_significant_genes(mm_de_tables, excel="excel/testing_sig_202010.xlsx"))
## Error in extract_significant_genes(mm_de_tables, excel = "excel/testing_sig_202010.xlsx"): object 'mm_de_tables' not found

1.7 Do PC analysis to look for variance wrt genotype

1.7.1 Look at PCs and their relationship to factors in the metadata

pc_raw <- pca_information(mm38_hisat, expt_factors=c("location", "genotype", "time", "condition"), num_factors=4)
## More shallow curves in these plots suggest more genes in this principle component.
pc_raw$pca_cor
##                PC1      PC2      PC3      PC4
## location   0.12983  0.14484 -0.32668 -0.03445
## genotype   0.07776 -0.14606  0.02969  0.48423
## time      -0.61235 -0.30192 -0.31319 -0.61949
## condition  0.11226 -0.09307 -0.07115  0.44364
pc_raw$anova_p
##                PC1    PC2    PC3      PC4
## location  0.554898 0.5096 0.1281 0.876002
## genotype  0.724337 0.5061 0.8930 0.019211
## time      0.001897 0.1615 0.1456 0.001619
## condition 0.610060 0.6728 0.7470 0.033967
pc_norm <- pca_information(mm38_norm_hi, expt_factors=c("location", "genotype", "time", "condition"), num_factors=4)
## More shallow curves in these plots suggest more genes in this principle component.
pc_norm$pca_cor
##                PC1     PC2      PC3     PC4
## location   0.03141 -0.2346  0.95040 -0.0168
## genotype  -0.03435 -0.1992 -0.01796  0.3055
## time       0.11061  0.8753  0.27578 -0.3471
## condition -0.02269 -0.2579  0.27116  0.2814
pc_norm$anova_p
##              PC1       PC2       PC3    PC4
## location  0.8869 2.813e-01 4.023e-12 0.9394
## genotype  0.8763 3.622e-01 9.352e-01 0.1563
## time      0.6154 4.583e-08 2.028e-01 0.1047
## condition 0.9181 2.349e-01 2.107e-01 0.1934
pc_nb <- pca_information(mm38_normbatch_hi,
                         expt_factors=c("location", "genotype", "time", "condition"),
                         num_factors=4, plot_pcas=TRUE)
## More shallow curves in these plots suggest more genes in this principle component.
pc_nb$pca_cor
##                PC1     PC2      PC3     PC4
## location  -0.04291 0.97563 -0.06657 -0.1112
## genotype  -0.13119 0.04489  0.30661 -0.1353
## time       0.17331 0.07804 -0.22464 -0.1243
## condition -0.13603 0.33774  0.26735 -0.1605
pc_nb$anova_p
##              PC1       PC2    PC3    PC4
## location  0.8458 2.583e-15 0.7628 0.6135
## genotype  0.5507 8.388e-01 0.1547 0.5383
## time      0.4290 7.234e-01 0.3028 0.5721
## condition 0.5360 1.150e-01 0.2175 0.4643
## It looks to me like PCs 2 and 3 are the most likely to be of interest with respect to
## genotype and location.
default_pca <- plot_pca(mm38_normbatch_hi)
default_pca$plot

## Here is what it looks like if we focus on PCs 2 and 3 instead:
pc_nb$pca_plots$PC2_PC3

all_three <- plot_3d_pca(default_pca, file="for_najib.html")
## Warning: `arrange_()` is deprecated as of dplyr 0.7.0.
## Please use `arrange()` instead.
## See vignette('programming') for more help
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
## I am not sure why, but it changed my colors!
all_three$plot

1.8 Do variance partition

We can make estimates about how many genes are related to the various factors with variancePartition.

mm38_varpart <- simple_varpart(mm38_norm_hi)
## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Dividing work into 100 chunks...
## Error in serialize(data, node$con, xdr = FALSE) : 
##   error writing to connection
## A couple of common errors:
## An error like 'vtv downdated' may be because there are too many 0s, filter the data and rerun.
## An error like 'number of levels of each grouping factor must be < number of observations' means
## that the factor used is not appropriate for the analysis - it really only works for factors
## which are shared among multiple samples.
## Retrying with only condition in the model.
## 
## Total:87 s
## Placing factor: condition at the beginning of the model.
pp(file="pre_varpart.png", image=mm38_varpart$partition_plot)
## Writing the image to: pre_varpart.png and calling dev.off().

mm38_nb_varpart <- simple_varpart(mm38_normbatch_hi)
## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Dividing work into 100 chunks...
## Error in serialize(data, node$con, xdr = FALSE) : 
##   error writing to connection
## A couple of common errors:
## An error like 'vtv downdated' may be because there are too many 0s, filter the data and rerun.
## An error like 'number of levels of each grouping factor must be < number of observations' means
## that the factor used is not appropriate for the analysis - it really only works for factors
## which are shared among multiple samples.
## Retrying with only condition in the model.
## 
## Total:88 s
## Placing factor: condition at the beginning of the model.
pp(file="post_varpart.png", image=mm38_nb_varpart$partition_plot)
## Writing the image to: post_varpart.png and calling dev.off().

This suggests there is some useful variance in the data which corresponds to genotype/location.

1.9 Perform gprofiler for:

1.9.1 het dlgn/retina

## mm_de_normal_sig
up_dlgn_ret <- mm_de_normal_sig[["deseq"]][["ups"]][["het_dlgnret"]]
rownames(up_dlgn_ret) <- gsub(x=rownames(up_dlgn_ret), pattern="gene:", replacement="")
up_dlgn_ret_gp <- simple_gprofiler(up_dlgn_ret, species="mmusculus", excel="excel/up_dlgn_ret_gp.xlsx")
## Performing gProfiler GO search of 2683 genes against mmusculus.
## GO search found 956 hits.
## Performing gProfiler KEGG search of 2683 genes against mmusculus.
## KEGG search found 55 hits.
## Performing gProfiler REAC search of 2683 genes against mmusculus.
## REAC search found 67 hits.
## Performing gProfiler MI search of 2683 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 2683 genes against mmusculus.
## TF search found 609 hits.
## Performing gProfiler CORUM search of 2683 genes against mmusculus.
## CORUM search found 4 hits.
## Performing gProfiler HP search of 2683 genes against mmusculus.
## HP search found 63 hits.
## Writing data to: excel/up_dlgn_ret_gp.xlsx.
## Finished writing data.
down_dlgn_ret <- mm_de_normal_sig[["deseq"]][["downs"]][["het_dlgnret"]]
rownames(down_dlgn_ret) <- gsub(x=rownames(down_dlgn_ret), pattern="gene:", replacement="")
down_dlgn_ret_gp <- simple_gprofiler(down_dlgn_ret, species="mmusculus", excel="excel/down_dlgn_ret_gp.xlsx")
## Performing gProfiler GO search of 2202 genes against mmusculus.
## GO search found 686 hits.
## Performing gProfiler KEGG search of 2202 genes against mmusculus.
## KEGG search found 19 hits.
## Performing gProfiler REAC search of 2202 genes against mmusculus.
## REAC search found 55 hits.
## Performing gProfiler MI search of 2202 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 2202 genes against mmusculus.
## TF search found 609 hits.
## Performing gProfiler CORUM search of 2202 genes against mmusculus.
## CORUM search found 3 hits.
## Performing gProfiler HP search of 2202 genes against mmusculus.
## HP search found 140 hits.
## Writing data to: excel/down_dlgn_ret_gp.xlsx.
## Finished writing data.

1.9.2 het scn/retina

## mm_de_normal_sig
up_scn_ret <- mm_de_normal_sig[["deseq"]][["ups"]][["het_scnret"]]
rownames(up_scn_ret) <- gsub(x=rownames(up_scn_ret), pattern="gene:", replacement="")
up_scn_ret_gp <- simple_gprofiler(up_scn_ret, species="mmusculus", excel="excel/up_scn_ret_gp.xlsx")
## Performing gProfiler GO search of 2422 genes against mmusculus.
## GO search found 728 hits.
## Performing gProfiler KEGG search of 2422 genes against mmusculus.
## KEGG search found 33 hits.
## Performing gProfiler REAC search of 2422 genes against mmusculus.
## REAC search found 44 hits.
## Performing gProfiler MI search of 2422 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 2422 genes against mmusculus.
## TF search found 577 hits.
## Performing gProfiler CORUM search of 2422 genes against mmusculus.
## CORUM search found 0 hits.
## Performing gProfiler HP search of 2422 genes against mmusculus.
## HP search found 42 hits.
## Writing data to: excel/up_scn_ret_gp.xlsx.
## Finished writing data.
down_scn_ret <- mm_de_normal_sig[["deseq"]][["downs"]][["het_scnret"]]
rownames(down_scn_ret) <- gsub(x=rownames(down_scn_ret), pattern="gene:", replacement="")
down_scn_ret_gp <- simple_gprofiler(down_scn_ret, species="mmusculus", excel="excel/down_scn_ret_gp.xlsx")
## Performing gProfiler GO search of 2358 genes against mmusculus.
## GO search found 690 hits.
## Performing gProfiler KEGG search of 2358 genes against mmusculus.
## KEGG search found 24 hits.
## Performing gProfiler REAC search of 2358 genes against mmusculus.
## REAC search found 49 hits.
## Performing gProfiler MI search of 2358 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 2358 genes against mmusculus.
## TF search found 713 hits.
## Performing gProfiler CORUM search of 2358 genes against mmusculus.
## CORUM search found 1 hits.
## Performing gProfiler HP search of 2358 genes against mmusculus.
## HP search found 92 hits.
## Writing data to: excel/down_scn_ret_gp.xlsx.
## Finished writing data.

1.9.3 het dlgn/scn

## mm_de_normal_sig
up_scn_ret <- mm_de_normal_sig[["deseq"]][["ups"]][["het_dlgnscn"]]
rownames(up_scn_ret) <- gsub(x=rownames(up_scn_ret), pattern="gene:", replacement="")
up_scn_ret_gp <- simple_gprofiler(up_scn_ret, species="mmusculus", excel="excel/up_dlgn_scn_gp.xlsx")
## Performing gProfiler GO search of 1202 genes against mmusculus.
## GO search found 612 hits.
## Performing gProfiler KEGG search of 1202 genes against mmusculus.
## KEGG search found 47 hits.
## Performing gProfiler REAC search of 1202 genes against mmusculus.
## REAC search found 30 hits.
## Performing gProfiler MI search of 1202 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 1202 genes against mmusculus.
## TF search found 454 hits.
## Performing gProfiler CORUM search of 1202 genes against mmusculus.
## CORUM search found 2 hits.
## Performing gProfiler HP search of 1202 genes against mmusculus.
## HP search found 28 hits.
## Writing data to: excel/up_dlgn_scn_gp.xlsx.
## Finished writing data.
down_scn_ret <- mm_de_normal_sig[["deseq"]][["downs"]][["het_dlgnscn"]]
rownames(down_scn_ret) <- gsub(x=rownames(down_scn_ret), pattern="gene:", replacement="")
down_scn_ret_gp <- simple_gprofiler(down_scn_ret, species="mmusculus", excel="excel/down_dlgn_scn_gp.xlsx")
## Performing gProfiler GO search of 996 genes against mmusculus.
## GO search found 196 hits.
## Performing gProfiler KEGG search of 996 genes against mmusculus.
## KEGG search found 9 hits.
## Performing gProfiler REAC search of 996 genes against mmusculus.
## REAC search found 12 hits.
## Performing gProfiler MI search of 996 genes against mmusculus.
## MI search found 0 hits.
## Performing gProfiler TF search of 996 genes against mmusculus.
## TF search found 311 hits.
## Performing gProfiler CORUM search of 996 genes against mmusculus.
## CORUM search found 3 hits.
## Performing gProfiler HP search of 996 genes against mmusculus.
## HP search found 25 hits.
## Writing data to: excel/down_dlgn_scn_gp.xlsx.
## Finished writing data.

1.10 Consider 3’ UTR for transcripts enriched in target

## The columns of likely interest:
## [199] "5_utr_start"
## [200] "5_utr_end"
## [201] "3_utr_start"
## [202] "3_utr_end"
length_requests <- c("ensembl_transcript_id", "cds_length", "chromosome_name",
                     "strand", "start_position", "end_position",
                     "5_utr_start", "5_utr_end", "3_utr_start", "3_utr_end")
mm_annot_v2 <- load_biomart_annotations(species="mmusculus", do_save=FALSE, overwrite=TRUE,
                                        length_requests=length_requests)
## Got a bad mart type when trying host Oct2019.archive.ensembl.org mart ENSEMBL_MART_ENSEMBL.
## Using mart: ENSEMBL_MART_ENSEMBL from host: Sep2019.archive.ensembl.org.
## Successfully connected to the mmusculus_gene_ensembl database.
## Finished downloading ensembl gene annotations.
## Finished downloading ensembl structure annotations.
## Dropping haplotype chromosome annotations, set drop_haplotypes=FALSE if this is bad.
## So, it turns out that there really are a _lot_ of utr differences depending on transcript
## Here are the few transcripts, it gets less encouraging after these.
head(mm_annot_v2[["annotation"]])
##                      ensembl_transcript_id    ensembl_gene_id version
## ENSMUST00000000001      ENSMUST00000000001 ENSMUSG00000000001       4
## ENSMUST00000000001.1    ENSMUST00000000001 ENSMUSG00000000001       4
## ENSMUST00000000001.2    ENSMUST00000000001 ENSMUSG00000000001       4
## ENSMUST00000000001.3    ENSMUST00000000001 ENSMUSG00000000001       4
## ENSMUST00000000003      ENSMUST00000000003 ENSMUSG00000000003      15
## ENSMUST00000000003.1    ENSMUST00000000003 ENSMUSG00000000003      15
##                      transcript_version hgnc_symbol
## ENSMUST00000000001                    4        <NA>
## ENSMUST00000000001.1                  4        <NA>
## ENSMUST00000000001.2                  4        <NA>
## ENSMUST00000000001.3                  4        <NA>
## ENSMUST00000000003                   13        <NA>
## ENSMUST00000000003.1                 13        <NA>
##                                                                                                               description
## ENSMUST00000000001   guanine nucleotide binding protein (G protein), alpha inhibiting 3 [Source:MGI Symbol;Acc:MGI:95773]
## ENSMUST00000000001.1 guanine nucleotide binding protein (G protein), alpha inhibiting 3 [Source:MGI Symbol;Acc:MGI:95773]
## ENSMUST00000000001.2 guanine nucleotide binding protein (G protein), alpha inhibiting 3 [Source:MGI Symbol;Acc:MGI:95773]
## ENSMUST00000000001.3 guanine nucleotide binding protein (G protein), alpha inhibiting 3 [Source:MGI Symbol;Acc:MGI:95773]
## ENSMUST00000000003                                                           probasin [Source:MGI Symbol;Acc:MGI:1860484]
## ENSMUST00000000003.1                                                         probasin [Source:MGI Symbol;Acc:MGI:1860484]
##                        gene_biotype cds_length chromosome_name strand
## ENSMUST00000000001   protein_coding       1065               3      -
## ENSMUST00000000001.1 protein_coding       1065               3      -
## ENSMUST00000000001.2 protein_coding       1065               3      -
## ENSMUST00000000001.3 protein_coding       1065               3      -
## ENSMUST00000000003   protein_coding        525               X      -
## ENSMUST00000000003.1 protein_coding        525               X      -
##                      start_position end_position 5_utr_start 5_utr_end
## ENSMUST00000000001        108107280    108146146          NA        NA
## ENSMUST00000000001.1      108107280    108146146   108146006 108146146
## ENSMUST00000000001.2      108107280    108146146          NA        NA
## ENSMUST00000000001.3      108107280    108146146          NA        NA
## ENSMUST00000000003         77837901     77853623          NA        NA
## ENSMUST00000000003.1       77837901     77853623          NA        NA
##                      3_utr_start 3_utr_end
## ENSMUST00000000001            NA        NA
## ENSMUST00000000001.1          NA        NA
## ENSMUST00000000001.2   108107280 108109316
## ENSMUST00000000001.3   108109403 108109421
## ENSMUST00000000003      77837901  77838114
## ENSMUST00000000003.1    77841860  77841882
## Maybe I can consider the first transcript for each gene which has the information for the 3' UTR?
test_up_lfc <- up_dlgn_ret[, c("deseq_logfc", "deseq_adjp")]
test_up_lfc[["threep_length"]] <- 0
test_down_lfc <- down_dlgn_ret[, c("deseq_logfc", "deseq_adjp")]
test_down_lfc[["threep_length"]] <- 0

mm <- mm_annot_v2[["annotation"]]
for (g in rownames(test_up_lfc)) {
  rows <- mm[["ensembl_gene_id"]] == g
  testers <- mm[rows, ]
  if (nrow(testers) == 0) {
    next
  }
  length <- 0
  for (tx in 1:nrow(testers)) {
    row <- testers[tx, ]
    if ((!is.na(row[["3_utr_start"]]) & !is.na(row[["3_utr_end"]]))) {
      length <- abs(row[["3_utr_start"]] - row[["3_utr_end"]])
    }
    if (length) {
      test_up_lfc[g, "threep_length"] <- length
      next
    }
  }
}


for (g in rownames(test_down_lfc)) {
  rows <- mm[["ensembl_gene_id"]] == g
  testers <- mm[rows, ]
  if (nrow(testers) == 0) {
    next
  }
  length <- 0
  for (tx in 1:nrow(testers)) {
    row <- testers[tx, ]
    if ((!is.na(row[["3_utr_start"]]) & !is.na(row[["3_utr_end"]]))) {
      length <- abs(row[["3_utr_start"]] - row[["3_utr_end"]])
    }
    if (length) {
      test_down_lfc[g, "threep_length"] <- length
      next
    }
  }
}

test_up_lfc[["direction"]] <- "up"
test_down_lfc[["direction"]] <- "down"
test_both <- rbind(test_up_lfc[, c("threep_length", "direction")],
                   test_down_lfc[, c("threep_length", "direction")])

multi <- ggplot2::ggplot(test_both,
                         aes(x=threep_length, fill=direction)) +
  ggplot2::geom_density(alpha=0.5) +
  ggplot2::scale_x_log10()
pp(file="nasty_histogram.png", image=multi)
## Writing the image to: nasty_histogram.png and calling dev.off().
## Warning: Transformation introduced infinite values in continuous x-axis
## Warning: Removed 147 rows containing non-finite values (stat_density).
## Warning: Transformation introduced infinite values in continuous x-axis
## Warning: Removed 147 rows containing non-finite values (stat_density).

Plot histogram of utr length for ups vs downs,

1.11 Interactive plot list

  • Volcano plot of het location/retina
  • Normal PCA including

2 Using an interaction model

## I changed the sample sheet so that the column is renamed to 'location'
## alt_model <- "~ location + location:genotype"
library(DESeq2)
## Loading required package: S4Vectors
## Loading required package: stats4
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:Matrix':
## 
##     expand
## The following object is masked from 'package:base':
## 
##     expand.grid
## Loading required package: IRanges
## Loading required package: GenomicRanges
## Loading required package: GenomeInfoDb
## Loading required package: SummarizedExperiment
## Loading required package: DelayedArray
## Loading required package: matrixStats
## 
## Attaching package: 'matrixStats'
## The following objects are masked from 'package:hpgltools':
## 
##     anyMissing, rowMedians
## The following objects are masked from 'package:Biobase':
## 
##     anyMissing, rowMedians
## 
## Attaching package: 'DelayedArray'
## The following objects are masked from 'package:matrixStats':
## 
##     colMaxs, colMins, colRanges, rowMaxs, rowMins, rowRanges
## The following objects are masked from 'package:base':
## 
##     aperm, apply, rowsum
alt_model <- "~ celltype + celltype:genotype"
metadata <- pData(mm_filt)
metadata[["location"]] <- factor(metadata[["location"]], levels=c("retina", "scn", "dlgn"))
metadata[["genotype"]] <- factor(metadata[["genotype"]], levels=c("wt", "ko", "het"))
dds <- DESeqDataSetFromMatrix(countData=exprs(mm_filt),
                              colData=metadata,
                              design=~0+location+genotype+genotype:location)
## converting counts to integer mode
dds_run <- DESeq(dds)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
resultsNames(dds_run)
## [1] "locationretina"           "locationscn"             
## [3] "locationdlgn"             "genotypeko"              
## [5] "genotypehet"              "locationscn.genotypeko"  
## [7] "locationdlgn.genotypeko"  "locationscn.genotypehet" 
## [9] "locationdlgn.genotypehet"
dlgn_vs_scn <- as.data.frame(results(dds_run, contrast=list("locationdlgn.genotypeko",
                                                            "locationscn.genotypeko")))
check <- is.na(dlgn_vs_scn[["padj"]])
dlgn_vs_scn[check, "padj"] <- 1
check <- dlgn_vs_scn[["padj"]] <= 0.1

2.0.1 Compare against the extra pairwise contrasts from limma

tables <- mm_limma$all_tables
## Error in eval(expr, envir, enclos): object 'mm_limma' not found
for (i in 1:length(tables)) {
  table_name <- names(tables)[i]
  table <- tables[[i]]
  print(table_name)
  t1 <- dlgn_vs_scn[, c("log2FoldChange", "pvalue")]
  t2 <- table[, c("logFC", "P.Value")]
  t3 <- merge(t1, t2, by="row.names")
  print(cor.test(t3[["log2FoldChange"]], t3[["logFC"]]))
}
## Error in eval(expr, envir, enclos): object 'tables' not found

2.1 Set up for initial analysis

Until we get full replicates, I will do simple subtractions.

2.1.1 Term definition

In an attempt to keep some clarity in the terms used, I want to define them now. There are three contexts in which we will consider the data:

  1. The individual sample type. When considering individual samples, I will use three terms in this and only this context: wild-type (wt), het, and mut.

  2. The individual translatome. These are defines as something / baseline. I will exclusively call the wt samples ‘baseline’ when speaking in this context. I will exclusively state ‘normal’ when referring to het / wt samples, and I will state ‘ko’ when referring to mut / wt samples in the translatome context.

  3. Translatome vs. translatome. Whenever comparing translatomes, I will use the names as in #2 and always put the numerator first when writing the name of a comparison.

The most complex example of the above nomenclature is:

“normko_retdlgn is defined as normret_vs_normdlgn - koret_vs_kodlgn”

This states we are examining at the translatome context: (norm(retina translatome) - norm(dlgn translatome)) - (ko(retina translatome) - ko(dlgn translatome))

Which in turn is synonymous to the following at the sample context: ((rethet - retwt) - (dlgnhet - dlgnwt)) - ((retko - retwt) - (dlgnko - dlgnwt))

Now let us associate the various variable names with the appropriate samples:

dlgnwt <- "iprgc_01"
retwt <- "iprgc_02"
scnwt <- "iprgc_03"

dlgnhet <- "iprgc_04"
rethet <- "iprgc_05"
scnhet <- NULL  ## Does not yet exist.

dlgnmut <- "iprgc_06"
retmut <- "iprgc_07"
scnmut <- "iprgc_08"

Give these variable names, now lets associate columns of the expression data with them. These are at the sample context, so the appropriate names are: ‘wt’, ‘het’, and ‘mut’. In each case I will prefix the genotype with the tissue type: ‘ret’, ‘dlgn’, and ‘scn’. Thus ‘retwt’ refers to the sample used to calculate the translatome retina baseline; in contrast ‘dlgnmut’ is the sample which provides the dlgn knockout.

## Sample context
mm38_norm <- mm_norm_sa
## Error in eval(expr, envir, enclos): object 'mm_norm_sa' not found
dlgnwt <- exprs(mm38_norm)[, dlgnwt]
retwt <- exprs(mm38_norm)[, retwt]
scnwt <- exprs(mm38_norm)[, scnwt]
dlgnhet <- exprs(mm38_norm)[, dlgnhet]
rethet <- exprs(mm38_norm)[, rethet]
dlgnmut <- exprs(mm38_norm)[, dlgnmut]
retmut <- exprs(mm38_norm)[, retmut]
scnmut <- exprs(mm38_norm)[, scnmut]

Each of the above 8 variables provides 1 column of information. We have 3 baseline comparisons available to us. In each of these we compare one wt sample to another.

## Baseline comparisons
wt_dlgnret <- dlgnwt - retwt
wt_scnret <- scnwt - retwt
wt_dlgnscn <- dlgnwt - scnwt

Simultaneously, we have 5 available translatomes. This are provided by comparing each het or mut to the associated wt. These will therefore receive names: ‘norm’ and ‘ko’ instead of ‘het’ and ‘mut’.

## Translatome context
normret <- rethet - retwt
koret <- retmut - retwt
koscn <- scnmut - scnwt
normdlgn <- dlgnhet - dlgnwt
kodlgn <- dlgnmut - dlgnwt

Given these translatomes, there are a few contrasts of likely interest. These are performed by comparing the relevant translatomes.

Will will split these into 4 separate categories: het vs het, ko vs ko, ko vs het, and ratio vs ratio.

Finally, note that we are being explicitly redundant in these definitions. I am making variable names for both the a/b ratio and the b/a ratio. Thus we have some redundantly redundant (haha) flexibility when deciding on what we want to plot.

## norm vs norm
normdlgn_vs_normret <- normdlgn - normret
normret_vs_normdlgn <- normret - normdlgn
## ko vs ko
koret_vs_kodlgn <- koret - kodlgn
kodlgn_vs_koret <- kodlgn - koret

koret_vs_koscn <- koret - koscn
koscn_vs_koret <- koscn - koret

kodlgn_vs_koscn <- kodlgn - koscn
koscn_vs_kodlgn <- koscn - kodlgn

On the other hand, I am assuming we always want the normals as denominators and kos as numerators.

## ko vs norm
koret_vs_normret <- koret - normret

kodlgn_vs_normdlgn <- kodlgn - normdlgn

Finally, here is the ratio of ratios example I printed above:

I named it ‘normko_retdlgn’ in an attempt to make clear that it is actually: (normret/normdlgn)/(koret/kodlgn)

or stated differently: “norm divided by ko for ret divided by dlgn.”

## ratio of ratios
normko_retdlgn <- normret_vs_normdlgn - koret_vs_kodlgn

2.2 Define a matrix of these values.

My matrix of data will now contain 1 column for each of the above 27 samples/comparisons.

pair_mtrx <- cbind(
  ## Individual samples
  dlgnwt, retwt, scnwt, dlgnhet, rethet, dlgnmut, retmut, scnmut,
  ## Baseline comparisons
  wt_dlgnret, wt_scnret, wt_dlgnscn,
  ## Baseline subtractions
  normdlgn, normret, kodlgn, koret, koscn,
  ## het_vs_het, of which there is only 1 because we do not have hetscn
  normdlgn_vs_normret, normret_vs_normdlgn,
  ## ko_vs_ko, of which we have 3
  koret_vs_kodlgn, kodlgn_vs_koret,
  koret_vs_koscn, koscn_vs_koret,
  kodlgn_vs_koscn, koscn_vs_kodlgn,
  ## ko_vs_het, 3 including one getting around missing hetscn
  koret_vs_normret, kodlgn_vs_normdlgn,
  ## ratio of ratios
  normko_retdlgn)

2.3 Cutoffs

I am not sure if we will use these indexes, but I am writing these out as subsets of genes to look at. These indexes are stating that, given a cutoff (0), we want to look at only the genes which have higher x / baseline values than the cutoff.

## Queries about gene subsets.
## These are all in the context of translatomes.
cutoff <- 0
ret_kept_idx <- normret > cutoff & koret > cutoff
scn_kept_idx <- koscn > cutoff
dlgn_kept_idx <- normdlgn > cutoff & kodlgn > cutoff
ret_dlgn_kept_idx <- ret_kept_idx & dlgn_kept_idx
ret_scn_kept_idx <- ret_kept_idx & scn_kept_idx
dlgn_scn_kept_idx <- dlgn_kept_idx & scn_kept_idx

##normdlgn_vs_normret[!ret_dlgn_kept_idx] <- NA
##normret_vs_normdlgn[!ret_dlgn_kept_idx] <- NA
##koret_vs_kodlgn[!ret_dlgn_kept_idx] <- NA
##kodlgn_vs_koret[!ret_dlgn_kept_idx] <- NA
##koret_vs_koscn[!ret_scn_kept_idx] <- NA
##koscn_vs_koret[!ret_scn_kept_idx] <- NA
##kodlgn_vs_koscn[!dlgn_scn_kept_idx] <- NA
##koscn_vs_kodlgn[!dlgn_scn_kept_idx] <- NA
##koret_vs_normret[!ret_kept_idx] <- NA
##kodlgn_vs_normdlgn[!dlgn_kept_idx] <- NA
##normko_retdlgn <- normko_retdlgn[!ret_dlgn_kept_idx] <- NA

2.4 Add the matrix to the differential expression

I will use my function combine_de_tables() to add this information to my existing annotation data along with the results from the statistically valid comparison of the three tissue types.

mm_tables <- sm(combine_de_tables(
  mm_de_sa, extra_annot=pair_mtrx,
  excel=glue::glue("excel/{rundate}mm_salmon_tables-v{ver}.xlsx")))

3 Plots of interesting comparisons

3.1 Retina, het vs. wt.

## Put retina baseline on y axis as black, retina het on x axis as black.
## Then recolor a subset of these as red, the reds are when normret > 0
library(ggplot2)

plotted <- as.data.frame(pair_mtrx[, c("rethet", "retwt")])
red_idx <- normret > 0
plotted[, "color"] <- ifelse(red_idx, "red", "black")
plotted[["label"]] <- rownames(plotted)
ret_hetwt <- ggplot(
  plotted,
  aes_string(x="rethet", y="retwt", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
ret_hetwt
ret_hetwt_clicky <- ggplotly_url(
  ret_hetwt, "ret_hetwt.html", title="Retina expression, het vs. wt.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.2 Retina, mut vs wt.

plotted <- as.data.frame(pair_mtrx[, c("retmut", "retwt")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
ret_mutwt <- ggplot(
  plotted,
  aes_string(x="retmut", y="retwt", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
ret_mutwt
ret_mutwt_clicky <- ggplotly_url(
  ret_mutwt, "ret_mutwt.html", title="Retina expression, mutant vs. wt.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.3 dlgn, het vs. wt.

plotted <- as.data.frame(pair_mtrx[, c("dlgnhet", "dlgnwt")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
dlgn_hetwt <- ggplot(
  plotted,
  aes_string(x="dlgnhet", y="dlgnwt", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
dlgn_hetwt
dlgn_hetwt_clicky <- ggplotly_url(
  dlgn_hetwt, "dlgn_hetwt.html", title="dlgn expression, het vs. wt.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.4 dlgn, mut vs. wt.

plotted <- as.data.frame(pair_mtrx[, c("dlgnmut", "dlgnwt")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
dlgn_mutwt <- ggplot(
  plotted,
  aes_string(x="dlgnmut", y="dlgnwt", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
dlgn_mutwt
dlgn_mutwt_clicky <- ggplotly_url(
  dlgn_mutwt, "dlgn_mutwt.html", title="dlgn expression, mut vs. wt.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.5 scn, mut vs. wt.

plotted <- as.data.frame(pair_mtrx[, c("scnmut", "scnwt")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
scn_mutwt <- ggplot(
  plotted,
  aes_string(x="scnmut", y="scnwt", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
scn_mutwt
scn_mutwt_clicky <- ggplotly_url(
  scn_mutwt, "scn_mutwt.html", title="scn expression, mut vs. wt.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.6 Axon translatome specific

##  x-axis: normdlgn_vs_normret or normret_vs_normdlgn,
##              ^^^^
##  y-axis: dlgnwt-retwt (baseline dlgn - baseline retina)
plotted <- as.data.frame(pair_mtrx[, c("normdlgn_vs_normret", "wt_dlgnret")])
red_idx <- normret > 0
## Note that this order is opposite of above.
plotted[, "color"] <- ifelse(red_idx, "black", "red")
plotted[["label"]] <- rownames(plotted)
axon_trans_ret_target <- ggplot(
  plotted,
  aes_string(x="normdlgn_vs_normret", y="wt_dlgnret", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
axon_trans_ret_target
axon_trans_ret_target_clicky <- ggplotly_url(
  axon_trans_ret_target, "axon_trans_ret_target.html", title="Axon translatome, retina target.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.7 DLGN translatome wrt. Retina translatome

plotted <- as.data.frame(pair_mtrx[, c("normret", "normdlgn")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
normret_normdlgn <- ggplot(
  plotted,
  aes_string(x="normret", y="normdlgn", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
normret_normdlgn
normret_normdlgn_clicky <- ggplotly_url(
  normret_normdlgn, "normret_normdlgn.html", title="Normal retina translatome vs normal dlgn translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.8 koret kodlgn

plotted <- as.data.frame(pair_mtrx[, c("koret", "kodlgn")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
koret_kodlgn <- ggplot(
  plotted,
  aes_string(x="koret", y="kodlgn", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
koret_kodlgn
koret_kodlgn_clicky <- ggplotly_url(
  koret_kodlgn, "koret_kodlgn.html", title="KO retina translatome vs KO dlgn translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.9 KO Retina vs KO SCN

plotted <- as.data.frame(pair_mtrx[, c("koret", "koscn")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
koret_koscn <- ggplot(
  plotted,
  aes_string(x="koret", y="koscn", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
koret_koscn
koret_koscn_clicky <- ggplotly_url(
  koret_koscn, "koret_koscn.html", title="KO retina translatome vs KO scn translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.10 Norm dlgn ko dlgn

plotted <- as.data.frame(pair_mtrx[, c("normdlgn", "kodlgn")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
normdlgn_kodlgn <- ggplot(
  plotted,
  aes_string(x="normdlgn", y="kodlgn", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
normdlgn_kodlgn
normdlgn_kodlgn_clicky <- ggplotly_url(
  normdlgn_kodlgn, "normdlgn_kodlgn.html", title="Normal dlgn translatome vs KO dlgn translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.11 Norm ret vs ko ret

plotted <- as.data.frame(pair_mtrx[, c("normret", "koret")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
normret_koret <- ggplot(
  plotted,
  aes_string(x="normret", y="koret", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
normret_koret
normret_koret_clicky <- ggplotly_url(
  normret_koret, "normret_koret.html", title="Normal retina translatome vs KO retina translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

3.12 ror

plotted <- as.data.frame(pair_mtrx[, c("normret_vs_normdlgn", "koret_vs_kodlgn")])
plotted[["label"]] <- rownames(plotted)
plotted[["color"]] <- "black"
normal_ko_axon_translatome <- ggplot(
  plotted,
  aes_string(x="normret_vs_normdlgn", y="koret_vs_kodlgn", label="label", color="color")) +
  geom_point(alpha=0.5) +
  scale_color_manual(values=c("black", "red"))
normal_ko_axon_translatome
normal_ko_axon_translatome_clicky <- ggplotly_url(
  normal_ko_axon_translatome, "normal_ko_axon_translatome.html",
  title="Normal retina ko axon translatome.",
  url_data="http://useast.ensembl.org/Mus_musculus/Gene/Summary?g={ids}")

4 Translatome level comparisons

4.1 Make a generic plotter for this stuff.

translatome_plotter <- function(pair_mtrx, x_axis="koret", y_axis="koscn", lfc=NULL, fc=NULL, linewidth=1.5,
                                up_color="red", down_color="#098534", line_color="#fcba03", alpha=0.5,
                                x_limit=c(-7, 7), y_limit=c(-7, 7)) {
  if (is.null(fc) & is.null(lfc)) {
    message("No fc/lfc was provided, defaulting to 10 fold.")
    lfc <- log2(10)
  } else if (is.null(lfc)) {
    lfc <- log2(fc)
  }
  plotted <- as.data.frame(pair_mtrx[, c(x_axis, y_axis)])
  na_idx <- is.na(plotted)
  plotted[na_idx] <- 0
  up_idx <- plotted[, y_axis] - plotted[, x_axis] >= lfc
  down_idx <- plotted[, y_axis] - plotted[, x_axis] <= (lfc * -1)
  up_genes <- rownames(plotted)[up_idx]
  down_genes <- rownames(plotted)[down_idx]
  ## Note that this order is opposite of above.
  plotted[["color"]] <- "black"
  plotted[up_idx, "color"] <- up_color
  plotted[down_idx, "color"] <- down_color
  plotted[["color"]] <- as.factor(plotted[["color"]])
  levels(plotted[["color"]]) <- c("black", up_color, down_color)
  plt <- ggplot2::ggplot(plotted, aes_string(x=x_axis,
                                             y=y_axis,
                                             color="color")) +
    geom_abline(size=1.1, slope=1, intercept=lfc, color="orange") +
    geom_abline(size=1.1, slope=1, intercept=(-1 * lfc), color="orange") +
    scale_x_continuous(limits=c(x_limit)) +
    scale_y_continuous(limits=c(y_limit)) +
    geom_point(alpha=alpha) +
    scale_color_manual(values=c(down_color, "black", up_color))
  retlist <- list(
    "mtrx" = plotted,
    "ups" = up_genes,
    "downs" = down_genes,
    "plot" = plt)
  return(retlist)
}
  1. X-axis: Always retina.
  2. Y-axis: Always a target tissue.

First plot: KO scn translatome on y axis vs. KO retina translatome on x axis.

4.2 Scn knockout translatome vs retina knockout translatome.

scnko_wrt_retko_translatome <- translatome_plotter(pair_mtrx)
scnko_wrt_retko_translatome$plot
scnko_wrt_retko_up_go <- simple_gprofiler(sig_genes=scnko_wrt_retko_translatome$ups,
                                          species="mmusculus")
scnko_wrt_retko_down_go <- simple_gprofiler(sig_genes=scnko_wrt_retko_translatome$downs,
                                            species="mmusculus")
scnko_wrt_retko_down_go$go
scnko_wrt_retko_down_go$kegg
scnko_wrt_retko_down_go$corum

4.3 dlgn normal translatome vs retina normal translatome.

dlgnnorm_wrt_retnorm_translatome <- translatome_plotter(pair_mtrx,
                                                        x_axis="normret", y_axis="normdlgn")
dlgnnorm_wrt_retnorm_translatome$plot
dlgnnorm_wrt_retnorm_up_go <- simple_gprofiler(sig_genes=dlgnnorm_wrt_retnorm_translatome$ups,
                                               species="mmusculus")
dlgnnorm_wrt_retnorm_down_go <- simple_gprofiler(sig_genes=dlgnnorm_wrt_retnorm_translatome$downs,
                                                 species="mmusculus")
dlgnnorm_wrt_retnorm_down_go$go
dlgnnorm_wrt_retnorm_down_go$pvalue_plots$bpp_plot_over
dlgnnorm_wrt_retnorm_down_go$pvalue_plots$ccp_plot_over

4.4 dlgn knockout translatome vs retina knockout translatome.

dlgnko_wrt_retko_translatome <- translatome_plotter(pair_mtrx,
                                                    x_axis="koret", y_axis="kodlgn")
dlgnko_wrt_retko_translatome$plot
dlgnko_wrt_retko_up_go <- simple_gprofiler(sig_genes=dlgnko_wrt_retko_translatome$ups,
                                           species="mmusculus")
dlgnko_wrt_retko_up_go$go
dlgnko_wrt_retko_up_go$kegg
dlgnko_wrt_retko_up_go$reac
dlgnko_wrt_retko_down_go <- simple_gprofiler(sig_genes=dlgnko_wrt_retko_translatome$downs,
                                             species="mmusculus")
dlgnko_wrt_retko_down_go$go
dlgnko_wrt_retko_down_go$kegg
dlgnko_wrt_retko_down_go$reac

4.5 Normal dlgn translatome vs knockout dlgn translatome.

dlgnnorm_wrt_dlgnko_translatome <- translatome_plotter(pair_mtrx,
                                                       x_axis="normdlgn",
                                                       y_axis="kodlgn")
dlgnnorm_wrt_dlgnko_translatome$plot
dlgnnorm_wrt_dlgnko_up_go <- simple_gprofiler(sig_genes=dlgnnorm_wrt_dlgnko_translatome$ups,
                                              species="mmusculus")
dlgnnorm_wrt_dlgnko_down_go <- simple_gprofiler(sig_genes=dlgnnorm_wrt_dlgnko_translatome$downs,
                                                species="mmusculus")
dlgnnorm_wrt_dlgnko_down_go$go

4.6 dlgn knockout translatome vs. scn knockout translatome.

dlgnko_wrt_scnko_translatome <- translatome_plotter(pair_mtrx,
                                                    x_axis="kodlgn",
                                                    y_axis="koscn")
dlgnko_wrt_scnko_translatome$plot
dlgnko_wrt_scnko_up_go <- simple_gprofiler(sig_genes=dlgnko_wrt_scnko_translatome$ups,
                                           species="mmusculus")
dlgnko_wrt_scnko_up_go$go
dlgnko_wrt_scnko_up_go$pvalue_plots$bpp_plot_over
dlgnko_wrt_scnko_down_go <- simple_gprofiler(sig_genes=dlgnko_wrt_scnko_translatome$downs,
                                             species="mmusculus")
dlgnko_wrt_scnko_down_go$go

5 Some pictures

As I understand it, there is some interest in an ontology search using the ratio of ratios.

ror <- normko_retdlgn
up_idx <- ror >= 1
down_idx <- ror <= -1
ror_up <- ror[up_idx]
length(ror_up)
ror_down <- ror[down_idx]
length(ror_down)

ror_gprofiler_up <- simple_gprofiler(
  sig_genes=ror_up, species="mmusculus",
  excel=glue::glue("excel/{rundate}mm_ror_gpfoiler_up-v{ver}.xlsx"))
ror_gprofiler_up$pvalue_plots$mfp_plot_over
ror_gprofiler_up$pvalue_plots$bpp_plot_over
ror_gprofiler_up$pvalue_plots$ccp_plot_over
ror_gprofiler_up$pvalue_plots$tf_plot_over
ror_gprofiler_up$pvalue_plots$hp_plot_over

ror_gprofiler_down <- simple_gprofiler(
  sig_genes=ror_down, species="mmusculus",
  excel=glue::glue("excel/{rundate}mm_ror_gpfoiler_down-v{ver}.xlsx"))
ror_gprofiler_down$pvalue_plots$mfp_plot_over
ror_gprofiler_down$pvalue_plots$bpp_plot_over
ror_gprofiler_down$pvalue_plots$reactome_plot_over
ror_gprofiler_down$pvalue_plots$ccp_plot_over
ror_gprofiler_down$pvalue_plots$tf_plot_over
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))
loadme(filename=this_save)
LS0tCnRpdGxlOiAiTS4gbXVzY3VsdXMgMyBjZWxsIHR5cGVzLCAxIHRpbWVwb2ludCwgMyBnZW5vdHlwZXMsIGFuZCAxIHJlcGxpY2F0ZS4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHdpZHRoOiAzMDAKICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5LCB0ZCB7CiAgZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDE2cHg7Cn0KcHJlIHsKIGZvbnQtc2l6ZTogMTZweAp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJocGdsdG9vbHMiKQp0dCA8LSBkZXZ0b29sczo6bG9hZF9hbGwoIi9kYXRhL2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQ9IiVZJW0lZCIpCnByZXZpb3VzX2ZpbGUgPC0gInVuZGVmaW5lZC5SbWQiCnZlciA8LSAiMjAyMDEwIgoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCnJtZF9maWxlIDwtICJpbmRleC5SbWQiCmBgYAoKIyBNLiBtdXNjdWx1cwoKVGhpcyB3aWxsIGJlIGEgdmVyeSBtaW5pbWFsIGFuYWx5c2lzIHVudGlsIHdlIGdldCBzb21lIHJlcGxpY2F0ZXMuCgojIyBBbm5vdGF0aW9ucwoKSSBhbSB1c2luZyBtbTM4XzEwMC4KCmBgYHtyIGFubm90YXRpb25zfQojIyBNeSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoKSBmdW5jdGlvbiBkZWZhdWx0cyB0byBodW1hbiwgc28gdGhhdCB3aWxsIGJlIHF1aWNrLgptbV9hbm5vdCA8LSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoc3BlY2llcz0ibW11c2N1bHVzIikKbW1fYW5ub3QgPC0gbW1fYW5ub3RbWyJhbm5vdGF0aW9uIl1dCm1tX2Fubm90W1sidHhpZCJdXSA8LSBwYXN0ZTAobW1fYW5ub3RbWyJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiXV0sICIuIiwgbW1fYW5ub3RbWyJ2ZXJzaW9uIl1dKQpyb3duYW1lcyhtbV9hbm5vdCkgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlPVRSVUUpCgp0eF9nZW5lX21hcCA8LSBtbV9hbm5vdFssIGMoInR4aWQiLCAiZW5zZW1ibF9nZW5lX2lkIildCmBgYAoKU28sIEkgbm93IGhhdmUgYSB0YWJsZSBvZiBtb3VzZSBhbm5vdGF0aW9ucy4KCiMjIE1ldGFkYXRhCgpJIGFtIGdvaW5nIHRvIHdyaXRlIGEgcXVpY2sgc2FtcGxlIHNoZWV0IGluIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGNhbGxlZAonYWxsX3NhbXBsZXMueGxzeCcgYW5kIHB1dCB0aGUgbmFtZXMgb2YgdGhlIGNvdW50IHRhYmxlcyBpbiBpdC4KCiMjIENyZWF0ZSBleHByZXNzaW9uc2V0cwoKSGVyZSBJIGNvbWJpbmUgdGhlIG1ldGFkYXRhLCBjb3VudCBkYXRhLCBhbmQgYW5ub3RhdGlvbnMuCgpJdCBpcyB3b3J0aCBub3RpbmcgdGhhdCB0aGUgZ2VuZSBJRHMgZnJvbSBodHNlcS1jb3VudCBwcm9iYWJseSBkbyBub3QgbWF0Y2ggdGhlCmFubm90YXRpb25zIHJldHJpZXZlZCBiZWNhdXNlIHRoZXkgYXJlIGxpa2VseSBleG9uLWJhc2VkIHJhdGhlciB0aGFuIGdlbmUKYmFzZWQuICBUaGlzIGlzIG5vdCByZWFsbHkgYSBwcm9ibGVtLCBidXQgZG9uJ3QgZm9yZ2V0IGl0IQoKIyMgSGlzYXQyIGV4cHJlc3Npb25zZXQKCmBgYHtyIGhpc2F0Mn0KaGlzYXRfYW5ub3QgPC0gbW1fYW5ub3QKcm93bmFtZXMoaGlzYXRfYW5ub3QpIDwtIHBhc3RlMCgiZ2VuZToiLCByb3duYW1lcyhoaXNhdF9hbm5vdCkpCm1tMzhfaGlzYXQgPC0gY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvYWxsX3NhbXBsZXMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvPWhpc2F0X2Fubm90KQoKcGxvdF9saWJzaXplKG1tMzhfaGlzYXQpJHBsb3QKbW0zOF9maXJzdCA8LSBub3JtYWxpemVfZXhwdChtbTM4X2hpc2F0LCBmaWx0ZXI9VFJVRSwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLCB0cmFuc2Zvcm09ImxvZzIiKQpwcChmaWxlPSJwcmVfcGNhLnBuZyIsIGltYWdlPXBsb3RfcGNhKG1tMzhfZmlyc3QpJHBsb3QpCgptbTM4X25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsIGJhdGNoPSJzdmFzZXEiKQptbTM4X25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9ub3JtLCB0cmFuc2Zvcm09ImxvZzIiKQpwcChmaWxlPSJwb3N0X3BjYS5wbmciLCBpbWFnZT1wbG90X3BjYShtbTM4X25vcm0pJHBsb3QpCmBgYAoKYGBge3Igc2FsbW9uX2V4cHR9Cm1tMzhfc2FsbW9uIDwtIGNyZWF0ZV9leHB0KCJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzLnhsc3giLCB0eF9nZW5lX21hcD10eF9nZW5lX21hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvPW1tX2Fubm90LCBmaWxlX2NvbHVtbj0ic2FsbW9uZmlsZSIpCgptbXR4X2Fubm90IDwtIG1tX2Fubm90CnJvd25hbWVzKG1tdHhfYW5ub3QpIDwtIG1tX2Fubm90W1sidHhpZCJdXQptbTM4X3NhbHR4IDwtIHNtKGNyZWF0ZV9leHB0KCJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1tbXR4X2Fubm90LCBmaWxlX2NvbHVtbj0ic2FsbW9uZmlsZSIpKQpgYGAKCiMjIFF1ZXJ5IGV4cHJlc3Npb25zZXRzCgpJbiB0aGlzIGJsb2NrIEkgd2lsbCBjYWxjdWxhdGUgYWxsIHRoZSBkaWFnbm9zdGljIHBsb3RzLCBidXQgbm90IHNob3cgdGhlbS4gIEkKd2lsbCBzaG93IHRoZW0gbmV4dCB3aXRoIGEgbGl0dGxlIGFubm90YXRpb24uCgpJIHdpbGwgbGVhdmUgdGhlIG91dHB1dCBmb3IgdGhlIGZpcnN0IG9mIGVhY2ggaW52b2NhdGlvbiBhbmQgc2lsZW5jZSBpdCBmb3IgdGhlIHNlY29uZC4KCiMjIyBJbml0aWFsIHNhbG1vbiBwbG90cwoKYGBge3IgcXVlcnlfc2FsbW9uLCBmaWcuc2hvdz0iaGlkZSJ9Cm1tMzhfcGxvdHNfc2EgPC0gc20oZ3JhcGhfbWV0cmljcyhtbTM4X3NhbG1vbikpCgptbTM4X25vcm1fc2EgPC0gbm9ybWFsaXplX2V4cHQobW0zOF9zYWxtb24sIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGZpbHRlcj1UUlVFKQoKbW0zOG5fcGxvdHNfc2EgPC0gZ3JhcGhfbWV0cmljcyhtbTM4X25vcm1fc2EpCmBgYAoKYGBge3Igc2hvd19wbG90c19zYWxtb259Cm1tMzhfcGxvdHNfc2EkbGVnZW5kCm1tMzhfcGxvdHNfc2EkbGlic2l6ZQptbTM4X3Bsb3RzX3NhJG5vbnplcm8KbW0zOG5fcGxvdHNfc2EkZGVuc2l0eQptbTM4bl9wbG90c19zYSRwY19wbG90CmBgYAoKIyMjIEluaXRpYWwgaGlzYXQyIHBsb3RzCgpgYGB7ciBxdWVyeV9oaXNhdCwgZmlnLnNob3c9ImhpZGUifQptbTM4X3Bsb3RzX2hpIDwtIHNtKGdyYXBoX21ldHJpY3MobW0zOF9oaXNhdCkpCgptbTM4X25vcm1faGkgPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdCwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIiwgZmlsdGVyPVRSVUUpCgptbTM4bl9wbG90c19oaSA8LSBzbShncmFwaF9tZXRyaWNzKG1tMzhfbm9ybV9oaSkpCgptbTM4X25vcm1iYXRjaF9oaSA8LSBub3JtYWxpemVfZXhwdChtbTM4X2hpc2F0LCBmaWx0ZXI9VFJVRSkKbW0zOF9ub3JtYmF0Y2hfaGkgPC0gbm9ybWFsaXplX2V4cHQobW0zOF9ub3JtYmF0Y2hfaGksIG5vcm09InF1YW50IiwgYmF0Y2g9InN2YXNlcSIpCm1tMzhfbm9ybWJhdGNoX2hpIDwtIG5vcm1hbGl6ZV9leHB0KG1tMzhfbm9ybWJhdGNoX2hpLCB0cmFuc2Zvcm09ImxvZzIiKQpgYGAKCmBgYHtyIHNob3dfcGxvdHNfaGlzYXR9Cm1tMzhfcGxvdHNfaGkkbGlic2l6ZQptbTM4X3Bsb3RzX2hpJG5vbnplcm8KbW0zOG5fcGxvdHNfaGkkZGVuc2l0eQptbTM4bl9wbG90c19oaSRwY19wbG90CmBgYAoKIyMgRG8gYSBzaW1wbGUgREUKClRoZSBvbmx5IGludGVyZXN0aW5nIERFIEkgc2VlIGluIHRoaXMgaXMgdG8gY29tcGFyZSB0aGUgcmV0aW5hcyB0byB0aGUgZGxnbnMuCkkgY2FuIHRyZWF0IHRoZW0gYXMgcmVwbGljYXRlcyBhbmQgY29tcGFyZS4KClRoZXNlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2VzIGFyZSBfRVhQTElDSVRMWV8gX05PVF8gd2hhdCB5b3UgY2FyZQphYm91dC4gIEhvd2V2ZXIsIHRoZXkgYXJlIHVzZWZ1bCBmb3IgdHdvIHB1cnBvc2VzOgoKMS4gIFNlZWluZyB0aGF0IHRoZSB0aHJlZSB0aXNzdWUgdHlwZXMgYXJlIGluZGVlZCBkaWZmZXJlbnQuCjIuICBTZXR0aW5nIHVwIHRoZSB0YWJsZSBvZiByZXN1bHRzIHdpdGggYXBwcm9wcmlhdGUgcm93cy9jb2x1bW5zIG9mIChyb3dzKWdlbmVzCiAgICBhbmQgKGNvbHVtbnMpIGFubm90YXRpb25zLiAgV2Ugd2lsbCB0aGVyZWZvcmUgYWRkIHRvIHRoZXNlIHRhYmxlcyB0aGUKICAgIHJlc3VsdHMgb2YgdGhlIGV4cHJlc3Npb24gYW5hbHlzZXMgdGhhdCB5b3UgYWN0dWFsbHkgZG8gY2FyZSBhYm91dC4KCldoZW4gd2UgcmVjZWl2ZSBmdWxsIHJlcGxpY2F0ZSBzZXRzLCB0aGlzIGNoZWF0ZXIgbWV0aG9kIG9mIGVuY2Fwc3VsYXRpbmcgdGhlCmRhdGEgd2lsbCBub3QgbG9uZ2VyIGJlIHJlcXVpcmVkLgoKIyMjIFdpdGggc2FsbW9uCgpgYGB7ciBkZV9zYSwgZmlnLnNob3c9ImhpZGUiLCBldmFsPUZBTFNFfQptbV9zYSA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG1tMzhfc2FsbW9uLCBmYWN0PSJjZWxsdHlwZSIpCm1tX25vcm1fc2EgPC0gc20obm9ybWFsaXplX2V4cHQobW1fc2EsIGNvbnZlcnQ9InJwa20iLCB0cmFuc2Zvcm09ImxvZzIiLCBjb2x1bW49ImNkc19sZW5ndGgiKSkKcGxvdF9wY2EobW1fbm9ybV9zYSkkcGxvdAoKbW1fZGVfc2EgPC0gYWxsX3BhaXJ3aXNlKG1tX3NhLCBtb2RlbF9iYXRjaD1GQUxTRSkKYGBgCgojIyMgV2l0aCBoaXNhdDIKCmBgYHtyIGRlX2hpLCBmaWcuc2hvdz0iaGlkZSJ9Cm5vcm1hbF9rZWVwZXJzIDwtIGxpc3QoCiAgInd0X2RsZ25yZXQiID0gYygid3RfZGxnbiIsICJ3dF9yZXRpbmEiKSwKICAid3Rfc2NucmV0IiA9IGMoInd0X3NjbiIsICJ3dF9yZXRpbmEiKSwKICAid3RfZGxnbnNjbiIgPSBjKCJ3dF9kbGduIiwgInd0X3NjbiIpLAogICJoZXRfZGxnbnJldCIgPSBjKCJoZXRfZGxnbiIsICJoZXRfcmV0aW5hIiksCiAgImhldF9zY25yZXQiID0gYygiaGV0X3NjbiIsICJoZXRfcmV0aW5hIiksCiAgImhldF9kbGduc2NuIiA9IGMoImhldF9kbGduIiwgImhldF9zY24iKSwKICAia29fZGxnbnJldCIgPSBjKCJrb19kbGduIiwgImtvX3JldGluYSIpLAogICJrb19zY25yZXQiID0gYygia29fc2NuIiwgImtvX3JldGluYSIpLAogICJrb19kbGduc2NuIiA9IGMoImtvX2RsZ24iLCAia29fc2NuIiksCiAgIm5vcm1yZXQiID0gYygiaGV0X3JldGluYSIsICJ3dF9yZXRpbmEiKSwKICAia29yZXQiID0gYygia29fcmV0aW5hIiwgInd0X3JldGluYSIpLAogICJub3Jtc2NuIiA9IGMoImhldF9zY24iLCAid3Rfc2NuIiksCiAgImtvc2NuIiA9IGMoImtvX3NjbiIsICJ3dF9zY24iKSwKICAibm9ybWRsZ24iID0gYygiaGV0X2RsZ24iLCAid3RfZGxnbiIpLAogICJrb2RsZ24iID0gYygia29fZGxnbiIsICJ3dF9kbGduIikKICApCgphbGxfa2VlcGVycyA8LSBsaXN0KAogICJ3dF9kbGducmV0IiA9IGMoInd0X2RsZ24iLCAid3RfcmV0aW5hIiksCiAgInd0X3NjbnJldCIgPSBjKCJ3dF9zY24iLCAid3RfcmV0aW5hIiksCiAgInd0X2RsZ25zY24iID0gYygid3RfZGxnbiIsICJ3dF9zY24iKSwKICAiaGV0X2RsZ25yZXQiID0gYygiaGV0X2RsZ24iLCAiaGV0X3JldGluYSIpLAogICJoZXRfc2NucmV0IiA9IGMoImhldF9zY24iLCAiaGV0X3JldGluYSIpLAogICJoZXRfZGxnbnNjbiIgPSBjKCJoZXRfZGxnbiIsICJoZXRfc2NuIiksCiAgImtvX2RsZ25yZXQiID0gYygia29fZGxnbiIsICJrb19yZXRpbmEiKSwKICAia29fc2NucmV0IiA9IGMoImtvX3NjbiIsICJrb19yZXRpbmEiKSwKICAia29fZGxnbnNjbiIgPSBjKCJrb19kbGduIiwgImtvX3NjbiIpLAogICJub3JtcmV0IiA9IGMoImhldF9yZXRpbmEiLCAid3RfcmV0aW5hIiksCiAgImtvcmV0IiA9IGMoImtvX3JldGluYSIsICJ3dF9yZXRpbmEiKSwKICAibm9ybXNjbiIgPSBjKCJoZXRfc2NuIiwgInd0X3NjbiIpLAogICJrb3NjbiIgPSBjKCJrb19zY24iLCAid3Rfc2NuIiksCiAgIm5vcm1kbGduIiA9IGMoImhldF9kbGduIiwgInd0X2RsZ24iKSwKICAia29kbGduIiA9IGMoImtvX2RsZ24iLCAid3RfZGxnbiIpLAogICJub3JtZGxnbl92c19ub3JtcmV0IiA9IGMoIm5vcm1kbGduIiwgIm5vcm1yZXQiKSwKICAibm9ybXNjbl92c19ub3JtcmV0IiA9IGMoIm5vcm1zY24iLCAibm9ybXJldCIpLAogICJrb2RsZ25fdnNfa29yZXQiID0gYygia29kbGduIiwgImtvcmV0IiksCiAgImtvc2NuX3ZzX2tvcmV0IiA9IGMoImtvc2NuIiwgImtvcmV0IiksCiAgImtvc2NuX3ZzX2tvZGxnbiIgPSBjKCJrb3NjbiIsICJrb2RsZ24iKSwKICAia29yZXRfdnNfbm9ybXJldCIgPSBjKCJrb19yZXRpbmEiLCAiaGV0X3JldGluYSIpLAogICJrb3Njbl92c19ub3Jtc2NuIiA9IGMoImtvX3NjbiIsICJoZXRfc2NuIiksCiAgImtvZGxnbl92c19ub3JtZGxnbiIgPSBjKCJrb19kbGduIiwgImhldF9kbGduIiksCiAgIm5vcm1rb19yZXRkbGduIiA9IGMoIm5vcm1kbGduX3ZzX25vcm1yZXQiLCAia29kbGduX3ZzX2tvcmV0IiksCiAgIm5vcm1rb19yZXRzY24iID0gYygibm9ybXNjbl92c19ub3JtcmV0IiwgImtvc2NuX3ZzX2tvcmV0IikpCgpleHRyYV9jb250cmFzdHMgPC0gIm5vcm1kbGduX3ZzX25vcm1yZXQgPSAoaGV0X2RsZ24td3RfZGxnbiktKGhldF9yZXRpbmEtd3RfcmV0aW5hKSwKICAgICAgICAgICBub3Jtc2NuX3ZzX25vcm1yZXQgPSAoaGV0X3Njbi13dF9zY24pLShoZXRfcmV0aW5hLXd0X3JldGluYSksCiAgICAgICAgICAga29kbGduX3ZzX2tvcmV0ID0gKGtvX2RsZ24td3RfZGxnbiktKGtvX3JldGluYS13dF9yZXRpbmEpLAogICAgICAgICAgIGtvc2NuX3ZzX2tvcmV0ID0gKGtvX3Njbi13dF9zY24pLShrb19yZXRpbmEtd3RfcmV0aW5hKSwKICAgICAgICAgICBrb3Njbl92c19rb2RsZ24gPSAoa29fc2NuLXd0X3NjbiktKGtvX2RsZ24td3RfZGxnbiksCiAgICAgICAgICAgbm9ybWtvX3ZzX3JldGRsZ24gPSAoKGhldF9kbGduLXd0X2RsZ24pLShoZXRfcmV0aW5hLXd0X3JldGluYSkpIC0gKChrb19kbGduLXd0X2RsZ24pLShrb19yZXRpbmEtd3RfcmV0aW5hKSksCiAgICAgICAgICAgbm9ybWtvX3ZzX3JldHNjbiA9ICgoaGV0X3Njbi13dF9zY24pLShoZXRfcmV0aW5hLXd0X3JldGluYSkpIC0gKChrb19zY24td3Rfc2NuKS0oa29fcmV0aW5hLXd0X3JldGluYSkpIgoKbW1fZmlsdCA8LSBub3JtYWxpemVfZXhwdChtbTM4X2hpc2F0LCBmaWx0ZXI9VFJVRSkKIyMgbW1fbGltbWEgPC0gc20obGltbWFfcGFpcndpc2UobW1fZmlsdCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGV4dHJhX2NvbnRyYXN0cz1leHRyYXMpKQptbV9kZXNlcSA8LSBkZXNlcV9wYWlyd2lzZShtbV9maWx0LCBtb2RlbF9iYXRjaD0ic3Zhc2VxIikKIyMgbW1fZWRnZXIgPC0gc20oZWRnZXJfcGFpcndpc2UobW1fZmlsdCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGV4dHJhX2NvbnRyYXN0cz1leHRyYXMpKQojIyBtbV9iYXNpYyA8LSBzbShiYXNpY19wYWlyd2lzZShtbV9maWx0LCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZXh0cmFfY29udHJhc3RzPWV4dHJhcykpCiMjIG1tX2Vic2VxIDwtIGVic2VxX3BhaXJ3aXNlKG1tX2ZpbHQsIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBleHRyYV9jb250cmFzdHM9ZXh0cmFzKQoKbW1fd3JpdGUgPC0gd3JpdGVfZXhwdChtbV9maWx0LCBleGNlbD0iZXhjZWwvcmF3X2RhdGFfYW5kX21ldHJpY3NfMjAyMDEwMzAueGxzeCIpCm1tX2RlX25vcm1hbCA8LSBhbGxfcGFpcndpc2UobW1fZmlsdCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIHBhcmFsbGVsPUZBTFNFLCBkb19lYnNlcT1GQUxTRSkKbW1fZGVfbm9ybWFsX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV9kZV9ub3JtYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ImV4Y2VsL29ubHlfcGFpcndpc2VfZGVfMjAyMDEwMzAueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycz1ub3JtYWxfa2VlcGVycykKbW1fZGVfbm9ybWFsX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX2RlX25vcm1hbF90YWJsZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD0iZXhjZWwvb25seV9wYWlyd2lzZV9zaWdfMjAyMDEwMzAueGxzeCIpCgp2b2wxIDwtIG1tX2RlX25vcm1hbF90YWJsZXNbWyJwbG90cyJdXVtbImhldF9kbGducmV0Il1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dW1sicGxvdCJdXQphbm5vdDEgPC0gbW1fZGVfbm9ybWFsX3RhYmxlc1tbImRhdGEiXV1bWyJoZXRfZGxnbnJldCJdXVtbImRlc2NyaXB0aW9uIl1dCnZvbDFbWyJkYXRhIl1dW1sibGFiZWwiXV0gPC0gYW5ub3QxCnZvbDFfZ2dwbG90bHkgPC0gZ2dwbHQoZ2c9dm9sMSwgZmlsZW5hbWU9InBsb3RzL3ZvbGNhbm9fZGxnbl92c19yZXRpbmEuaHRtbCIpCnZvbDIgPC0gbW1fZGVfbm9ybWFsX3RhYmxlc1tbInBsb3RzIl1dW1siaGV0X3NjbnJldCJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXVtbInBsb3QiXV0KYW5ub3QyIDwtIG1tX2RlX25vcm1hbF90YWJsZXNbWyJkYXRhIl1dW1siaGV0X3NjbnJldCJdXVtbImRlc2NyaXB0aW9uIl1dCnZvbDJbWyJkYXRhIl1dW1sibGFiZWwiXV0gPC0gYW5ub3QyCnZvbDJfZ2dwbG90bHkgPC0gZ2dwbHQoZ2c9dm9sMiwgZmlsZW5hbWU9InZvbGNhbm9fc2NuX3ZzX3JldGluYS5odG1sIikKdm9sMyA8LSBtbV9kZV9ub3JtYWxfdGFibGVzW1sicGxvdHMiXV1bWyJoZXRfZGxnbnNjbiJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXVtbInBsb3QiXV0KYW5ub3QzIDwtIG1tX2RlX25vcm1hbF90YWJsZXNbWyJkYXRhIl1dW1siaGV0X2RsZ25zY24iXV1bWyJkZXNjcmlwdGlvbiJdXQp2b2wzW1siZGF0YSJdXVtbImxhYmVsIl1dIDwtIGFubm90Mwp2b2wzX2dncGxvdGx5IDwtIGdncGx0KGdnPXZvbDMsIGZpbGVuYW1lPSJ2b2xjYW5vX2RsZ25fdnNfc2NuLmh0bWwiKQpgYGAKCmBgYHtyIGRlX2ZhbmN5fQptbV9kZV9oaSA8LSBzbShhbGxfcGFpcndpc2UobW1fZmlsdCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIHBhcmFsbGVsPUZBTFNFLCBleHRyYV9jb250cmFzdHM9ZXh0cmFzKSkKCm1tX2RlX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhtbV9kZV9oaSwgZXhjZWw9ImV4Y2VsL3Rlc3RpbmdfMjAyMDEwMzAueGxzeCIsIGtlZXBlcnM9a2VlcGVycykpCm1tX2RlX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX2RlX3RhYmxlcywgZXhjZWw9ImV4Y2VsL3Rlc3Rpbmdfc2lnXzIwMjAxMC54bHN4IikpCmBgYAoKIyMgRG8gUEMgYW5hbHlzaXMgdG8gbG9vayBmb3IgdmFyaWFuY2Ugd3J0IGdlbm90eXBlCgojIyMgTG9vayBhdCBQQ3MgYW5kIHRoZWlyIHJlbGF0aW9uc2hpcCB0byBmYWN0b3JzIGluIHRoZSBtZXRhZGF0YQoKYGBge3IgcGNfaW5mb3JtYXRpb24sIGZpZy5zaG93PSJoaWRlIn0KcGNfcmF3IDwtIHBjYV9pbmZvcm1hdGlvbihtbTM4X2hpc2F0LCBleHB0X2ZhY3RvcnM9YygibG9jYXRpb24iLCAiZ2Vub3R5cGUiLCAidGltZSIsICJjb25kaXRpb24iKSwgbnVtX2ZhY3RvcnM9NCkKcGNfcmF3JHBjYV9jb3IKcGNfcmF3JGFub3ZhX3AKCnBjX25vcm0gPC0gcGNhX2luZm9ybWF0aW9uKG1tMzhfbm9ybV9oaSwgZXhwdF9mYWN0b3JzPWMoImxvY2F0aW9uIiwgImdlbm90eXBlIiwgInRpbWUiLCAiY29uZGl0aW9uIiksIG51bV9mYWN0b3JzPTQpCnBjX25vcm0kcGNhX2NvcgpwY19ub3JtJGFub3ZhX3AKCnBjX25iIDwtIHBjYV9pbmZvcm1hdGlvbihtbTM4X25vcm1iYXRjaF9oaSwKICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHRfZmFjdG9ycz1jKCJsb2NhdGlvbiIsICJnZW5vdHlwZSIsICJ0aW1lIiwgImNvbmRpdGlvbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgbnVtX2ZhY3RvcnM9NCwgcGxvdF9wY2FzPVRSVUUpCnBjX25iJHBjYV9jb3IKcGNfbmIkYW5vdmFfcAojIyBJdCBsb29rcyB0byBtZSBsaWtlIFBDcyAyIGFuZCAzIGFyZSB0aGUgbW9zdCBsaWtlbHkgdG8gYmUgb2YgaW50ZXJlc3Qgd2l0aCByZXNwZWN0IHRvCiMjIGdlbm90eXBlIGFuZCBsb2NhdGlvbi4KYGBgCgpgYGB7ciBwY19pbmZvcm1hdGlvbl9wbG90c30KZGVmYXVsdF9wY2EgPC0gcGxvdF9wY2EobW0zOF9ub3JtYmF0Y2hfaGkpCmRlZmF1bHRfcGNhJHBsb3QKCiMjIEhlcmUgaXMgd2hhdCBpdCBsb29rcyBsaWtlIGlmIHdlIGZvY3VzIG9uIFBDcyAyIGFuZCAzIGluc3RlYWQ6CnBjX25iJHBjYV9wbG90cyRQQzJfUEMzCgphbGxfdGhyZWUgPC0gcGxvdF8zZF9wY2EoZGVmYXVsdF9wY2EsIGZpbGU9ImZvcl9uYWppYi5odG1sIikKIyMgSSBhbSBub3Qgc3VyZSB3aHksIGJ1dCBpdCBjaGFuZ2VkIG15IGNvbG9ycyEKYWxsX3RocmVlJHBsb3QKYGBgCgojIyBEbyB2YXJpYW5jZSBwYXJ0aXRpb24KCldlIGNhbiBtYWtlIGVzdGltYXRlcyBhYm91dCBob3cgbWFueSBnZW5lcyBhcmUgcmVsYXRlZCB0byB0aGUgdmFyaW91cyBmYWN0b3JzIHdpdGggdmFyaWFuY2VQYXJ0aXRpb24uCgpgYGB7ciB2cH0KbW0zOF92YXJwYXJ0IDwtIHNpbXBsZV92YXJwYXJ0KG1tMzhfbm9ybV9oaSkKcHAoZmlsZT0icHJlX3ZhcnBhcnQucG5nIiwgaW1hZ2U9bW0zOF92YXJwYXJ0JHBhcnRpdGlvbl9wbG90KQoKbW0zOF9uYl92YXJwYXJ0IDwtIHNpbXBsZV92YXJwYXJ0KG1tMzhfbm9ybWJhdGNoX2hpKQpwcChmaWxlPSJwb3N0X3ZhcnBhcnQucG5nIiwgaW1hZ2U9bW0zOF9uYl92YXJwYXJ0JHBhcnRpdGlvbl9wbG90KQpgYGAKClRoaXMgc3VnZ2VzdHMgdGhlcmUgaXMgc29tZSB1c2VmdWwgdmFyaWFuY2UgaW4gdGhlIGRhdGEgd2hpY2ggY29ycmVzcG9uZHMgdG8gZ2Vub3R5cGUvbG9jYXRpb24uCgojIyBQZXJmb3JtIGdwcm9maWxlciBmb3I6CgojIyMgaGV0IGRsZ24vcmV0aW5hCgpgYGB7ciBncF9kbGduX3JldGluYX0KIyMgbW1fZGVfbm9ybWFsX3NpZwp1cF9kbGduX3JldCA8LSBtbV9kZV9ub3JtYWxfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJoZXRfZGxnbnJldCJdXQpyb3duYW1lcyh1cF9kbGduX3JldCkgPC0gZ3N1Yih4PXJvd25hbWVzKHVwX2RsZ25fcmV0KSwgcGF0dGVybj0iZ2VuZToiLCByZXBsYWNlbWVudD0iIikKdXBfZGxnbl9yZXRfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcih1cF9kbGduX3JldCwgc3BlY2llcz0ibW11c2N1bHVzIiwgZXhjZWw9ImV4Y2VsL3VwX2RsZ25fcmV0X2dwLnhsc3giKQpkb3duX2RsZ25fcmV0IDwtIG1tX2RlX25vcm1hbF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siaGV0X2RsZ25yZXQiXV0Kcm93bmFtZXMoZG93bl9kbGduX3JldCkgPC0gZ3N1Yih4PXJvd25hbWVzKGRvd25fZGxnbl9yZXQpLCBwYXR0ZXJuPSJnZW5lOiIsIHJlcGxhY2VtZW50PSIiKQpkb3duX2RsZ25fcmV0X2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoZG93bl9kbGduX3JldCwgc3BlY2llcz0ibW11c2N1bHVzIiwgZXhjZWw9ImV4Y2VsL2Rvd25fZGxnbl9yZXRfZ3AueGxzeCIpCmBgYAoKIyMjIGhldCBzY24vcmV0aW5hCgpgYGB7ciBncF9zY25fcmV0aW5hfQojIyBtbV9kZV9ub3JtYWxfc2lnCnVwX3Njbl9yZXQgPC0gbW1fZGVfbm9ybWFsX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siaGV0X3NjbnJldCJdXQpyb3duYW1lcyh1cF9zY25fcmV0KSA8LSBnc3ViKHg9cm93bmFtZXModXBfc2NuX3JldCksIHBhdHRlcm49ImdlbmU6IiwgcmVwbGFjZW1lbnQ9IiIpCnVwX3Njbl9yZXRfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcih1cF9zY25fcmV0LCBzcGVjaWVzPSJtbXVzY3VsdXMiLCBleGNlbD0iZXhjZWwvdXBfc2NuX3JldF9ncC54bHN4IikKZG93bl9zY25fcmV0IDwtIG1tX2RlX25vcm1hbF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siaGV0X3NjbnJldCJdXQpyb3duYW1lcyhkb3duX3Njbl9yZXQpIDwtIGdzdWIoeD1yb3duYW1lcyhkb3duX3Njbl9yZXQpLCBwYXR0ZXJuPSJnZW5lOiIsIHJlcGxhY2VtZW50PSIiKQpkb3duX3Njbl9yZXRfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihkb3duX3Njbl9yZXQsIHNwZWNpZXM9Im1tdXNjdWx1cyIsIGV4Y2VsPSJleGNlbC9kb3duX3Njbl9yZXRfZ3AueGxzeCIpCmBgYAoKIyMjIGhldCBkbGduL3NjbgoKYGBge3IgZ3Bfc2NuZGxnbn0KIyMgbW1fZGVfbm9ybWFsX3NpZwp1cF9zY25fcmV0IDwtIG1tX2RlX25vcm1hbF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImhldF9kbGduc2NuIl1dCnJvd25hbWVzKHVwX3Njbl9yZXQpIDwtIGdzdWIoeD1yb3duYW1lcyh1cF9zY25fcmV0KSwgcGF0dGVybj0iZ2VuZToiLCByZXBsYWNlbWVudD0iIikKdXBfc2NuX3JldF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHVwX3Njbl9yZXQsIHNwZWNpZXM9Im1tdXNjdWx1cyIsIGV4Y2VsPSJleGNlbC91cF9kbGduX3Njbl9ncC54bHN4IikKZG93bl9zY25fcmV0IDwtIG1tX2RlX25vcm1hbF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siaGV0X2RsZ25zY24iXV0Kcm93bmFtZXMoZG93bl9zY25fcmV0KSA8LSBnc3ViKHg9cm93bmFtZXMoZG93bl9zY25fcmV0KSwgcGF0dGVybj0iZ2VuZToiLCByZXBsYWNlbWVudD0iIikKZG93bl9zY25fcmV0X2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoZG93bl9zY25fcmV0LCBzcGVjaWVzPSJtbXVzY3VsdXMiLCBleGNlbD0iZXhjZWwvZG93bl9kbGduX3Njbl9ncC54bHN4IikKYGBgCgojIyBDb25zaWRlciAzJyBVVFIgZm9yIHRyYW5zY3JpcHRzIGVucmljaGVkIGluIHRhcmdldAoKYGBge3IgdXRyX3VwX2Rvd259CiMjIFRoZSBjb2x1bW5zIG9mIGxpa2VseSBpbnRlcmVzdDoKIyMgWzE5OV0gIjVfdXRyX3N0YXJ0IgojIyBbMjAwXSAiNV91dHJfZW5kIgojIyBbMjAxXSAiM191dHJfc3RhcnQiCiMjIFsyMDJdICIzX3V0cl9lbmQiCmxlbmd0aF9yZXF1ZXN0cyA8LSBjKCJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLCAiY2RzX2xlbmd0aCIsICJjaHJvbW9zb21lX25hbWUiLAogICAgICAgICAgICAgICAgICAgICAic3RyYW5kIiwgInN0YXJ0X3Bvc2l0aW9uIiwgImVuZF9wb3NpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICI1X3V0cl9zdGFydCIsICI1X3V0cl9lbmQiLCAiM191dHJfc3RhcnQiLCAiM191dHJfZW5kIikKbW1fYW5ub3RfdjIgPC0gbG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHNwZWNpZXM9Im1tdXNjdWx1cyIsIGRvX3NhdmU9RkFMU0UsIG92ZXJ3cml0ZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX3JlcXVlc3RzPWxlbmd0aF9yZXF1ZXN0cykKIyMgU28sIGl0IHR1cm5zIG91dCB0aGF0IHRoZXJlIHJlYWxseSBhcmUgYSBfbG90XyBvZiB1dHIgZGlmZmVyZW5jZXMgZGVwZW5kaW5nIG9uIHRyYW5zY3JpcHQKIyMgSGVyZSBhcmUgdGhlIGZldyB0cmFuc2NyaXB0cywgaXQgZ2V0cyBsZXNzIGVuY291cmFnaW5nIGFmdGVyIHRoZXNlLgpoZWFkKG1tX2Fubm90X3YyW1siYW5ub3RhdGlvbiJdXSkKIyMgTWF5YmUgSSBjYW4gY29uc2lkZXIgdGhlIGZpcnN0IHRyYW5zY3JpcHQgZm9yIGVhY2ggZ2VuZSB3aGljaCBoYXMgdGhlIGluZm9ybWF0aW9uIGZvciB0aGUgMycgVVRSPwp0ZXN0X3VwX2xmYyA8LSB1cF9kbGduX3JldFssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KdGVzdF91cF9sZmNbWyJ0aHJlZXBfbGVuZ3RoIl1dIDwtIDAKdGVzdF9kb3duX2xmYyA8LSBkb3duX2RsZ25fcmV0WywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQp0ZXN0X2Rvd25fbGZjW1sidGhyZWVwX2xlbmd0aCJdXSA8LSAwCgptbSA8LSBtbV9hbm5vdF92MltbImFubm90YXRpb24iXV0KZm9yIChnIGluIHJvd25hbWVzKHRlc3RfdXBfbGZjKSkgewogIHJvd3MgPC0gbW1bWyJlbnNlbWJsX2dlbmVfaWQiXV0gPT0gZwogIHRlc3RlcnMgPC0gbW1bcm93cywgXQogIGlmIChucm93KHRlc3RlcnMpID09IDApIHsKICAgIG5leHQKICB9CiAgbGVuZ3RoIDwtIDAKICBmb3IgKHR4IGluIDE6bnJvdyh0ZXN0ZXJzKSkgewogICAgcm93IDwtIHRlc3RlcnNbdHgsIF0KICAgIGlmICgoIWlzLm5hKHJvd1tbIjNfdXRyX3N0YXJ0Il1dKSAmICFpcy5uYShyb3dbWyIzX3V0cl9lbmQiXV0pKSkgewogICAgICBsZW5ndGggPC0gYWJzKHJvd1tbIjNfdXRyX3N0YXJ0Il1dIC0gcm93W1siM191dHJfZW5kIl1dKQogICAgfQogICAgaWYgKGxlbmd0aCkgewogICAgICB0ZXN0X3VwX2xmY1tnLCAidGhyZWVwX2xlbmd0aCJdIDwtIGxlbmd0aAogICAgICBuZXh0CiAgICB9CiAgfQp9CgoKZm9yIChnIGluIHJvd25hbWVzKHRlc3RfZG93bl9sZmMpKSB7CiAgcm93cyA8LSBtbVtbImVuc2VtYmxfZ2VuZV9pZCJdXSA9PSBnCiAgdGVzdGVycyA8LSBtbVtyb3dzLCBdCiAgaWYgKG5yb3codGVzdGVycykgPT0gMCkgewogICAgbmV4dAogIH0KICBsZW5ndGggPC0gMAogIGZvciAodHggaW4gMTpucm93KHRlc3RlcnMpKSB7CiAgICByb3cgPC0gdGVzdGVyc1t0eCwgXQogICAgaWYgKCghaXMubmEocm93W1siM191dHJfc3RhcnQiXV0pICYgIWlzLm5hKHJvd1tbIjNfdXRyX2VuZCJdXSkpKSB7CiAgICAgIGxlbmd0aCA8LSBhYnMocm93W1siM191dHJfc3RhcnQiXV0gLSByb3dbWyIzX3V0cl9lbmQiXV0pCiAgICB9CiAgICBpZiAobGVuZ3RoKSB7CiAgICAgIHRlc3RfZG93bl9sZmNbZywgInRocmVlcF9sZW5ndGgiXSA8LSBsZW5ndGgKICAgICAgbmV4dAogICAgfQogIH0KfQoKdGVzdF91cF9sZmNbWyJkaXJlY3Rpb24iXV0gPC0gInVwIgp0ZXN0X2Rvd25fbGZjW1siZGlyZWN0aW9uIl1dIDwtICJkb3duIgp0ZXN0X2JvdGggPC0gcmJpbmQodGVzdF91cF9sZmNbLCBjKCJ0aHJlZXBfbGVuZ3RoIiwgImRpcmVjdGlvbiIpXSwKICAgICAgICAgICAgICAgICAgIHRlc3RfZG93bl9sZmNbLCBjKCJ0aHJlZXBfbGVuZ3RoIiwgImRpcmVjdGlvbiIpXSkKCm11bHRpIDwtIGdncGxvdDI6OmdncGxvdCh0ZXN0X2JvdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD10aHJlZXBfbGVuZ3RoLCBmaWxsPWRpcmVjdGlvbikpICsKICBnZ3Bsb3QyOjpnZW9tX2RlbnNpdHkoYWxwaGE9MC41KSArCiAgZ2dwbG90Mjo6c2NhbGVfeF9sb2cxMCgpCnBwKGZpbGU9Im5hc3R5X2hpc3RvZ3JhbS5wbmciLCBpbWFnZT1tdWx0aSkKCmBgYAoKUGxvdCBoaXN0b2dyYW0gb2YgdXRyIGxlbmd0aCBmb3IgdXBzIHZzIGRvd25zLAoKIyMgSW50ZXJhY3RpdmUgcGxvdCBsaXN0CgoqIFZvbGNhbm8gcGxvdCBvZiBoZXQgbG9jYXRpb24vcmV0aW5hCiogTm9ybWFsIFBDQSBpbmNsdWRpbmcKCiMgVXNpbmcgYW4gaW50ZXJhY3Rpb24gbW9kZWwKCmBgYHtyIGludGVyYWN0aW9uX21vZGVsfQojIyBJIGNoYW5nZWQgdGhlIHNhbXBsZSBzaGVldCBzbyB0aGF0IHRoZSBjb2x1bW4gaXMgcmVuYW1lZCB0byAnbG9jYXRpb24nCiMjIGFsdF9tb2RlbCA8LSAifiBsb2NhdGlvbiArIGxvY2F0aW9uOmdlbm90eXBlIgpsaWJyYXJ5KERFU2VxMikKYWx0X21vZGVsIDwtICJ+IGNlbGx0eXBlICsgY2VsbHR5cGU6Z2Vub3R5cGUiCm1ldGFkYXRhIDwtIHBEYXRhKG1tX2ZpbHQpCm1ldGFkYXRhW1sibG9jYXRpb24iXV0gPC0gZmFjdG9yKG1ldGFkYXRhW1sibG9jYXRpb24iXV0sIGxldmVscz1jKCJyZXRpbmEiLCAic2NuIiwgImRsZ24iKSkKbWV0YWRhdGFbWyJnZW5vdHlwZSJdXSA8LSBmYWN0b3IobWV0YWRhdGFbWyJnZW5vdHlwZSJdXSwgbGV2ZWxzPWMoInd0IiwgImtvIiwgImhldCIpKQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGE9ZXhwcnMobW1fZmlsdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGE9bWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbj1+MCtsb2NhdGlvbitnZW5vdHlwZStnZW5vdHlwZTpsb2NhdGlvbikKZGRzX3J1biA8LSBERVNlcShkZHMpCnJlc3VsdHNOYW1lcyhkZHNfcnVuKQoKZGxnbl92c19zY24gPC0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKGRkc19ydW4sIGNvbnRyYXN0PWxpc3QoImxvY2F0aW9uZGxnbi5nZW5vdHlwZWtvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxvY2F0aW9uc2NuLmdlbm90eXBla28iKSkpCmNoZWNrIDwtIGlzLm5hKGRsZ25fdnNfc2NuW1sicGFkaiJdXSkKZGxnbl92c19zY25bY2hlY2ssICJwYWRqIl0gPC0gMQpjaGVjayA8LSBkbGduX3ZzX3NjbltbInBhZGoiXV0gPD0gMC4xCmBgYAoKIyMjIENvbXBhcmUgYWdhaW5zdCB0aGUgZXh0cmEgcGFpcndpc2UgY29udHJhc3RzIGZyb20gbGltbWEKCmBgYHtyIGNvbXBhcmVfbGltbWF9CnRhYmxlcyA8LSBtbV9saW1tYSRhbGxfdGFibGVzCmZvciAoaSBpbiAxOmxlbmd0aCh0YWJsZXMpKSB7CiAgdGFibGVfbmFtZSA8LSBuYW1lcyh0YWJsZXMpW2ldCiAgdGFibGUgPC0gdGFibGVzW1tpXV0KICBwcmludCh0YWJsZV9uYW1lKQogIHQxIDwtIGRsZ25fdnNfc2NuWywgYygibG9nMkZvbGRDaGFuZ2UiLCAicHZhbHVlIildCiAgdDIgPC0gdGFibGVbLCBjKCJsb2dGQyIsICJQLlZhbHVlIildCiAgdDMgPC0gbWVyZ2UodDEsIHQyLCBieT0icm93Lm5hbWVzIikKICBwcmludChjb3IudGVzdCh0M1tbImxvZzJGb2xkQ2hhbmdlIl1dLCB0M1tbImxvZ0ZDIl1dKSkKfQpgYGAKCiMjIFNldCB1cCBmb3IgaW5pdGlhbCBhbmFseXNpcwoKVW50aWwgd2UgZ2V0IGZ1bGwgcmVwbGljYXRlcywgSSB3aWxsIGRvIHNpbXBsZSBzdWJ0cmFjdGlvbnMuCgojIyMgVGVybSBkZWZpbml0aW9uCgpJbiBhbiBhdHRlbXB0IHRvIGtlZXAgc29tZSBjbGFyaXR5IGluIHRoZSB0ZXJtcyB1c2VkLCBJIHdhbnQgdG8gZGVmaW5lIHRoZW0Kbm93LiAgVGhlcmUgYXJlIHRocmVlIGNvbnRleHRzIGluIHdoaWNoIHdlIHdpbGwgY29uc2lkZXIgdGhlIGRhdGE6CgoxLiAgVGhlIGluZGl2aWR1YWwgc2FtcGxlIHR5cGUuICBXaGVuIGNvbnNpZGVyaW5nIGluZGl2aWR1YWwgc2FtcGxlcywgSSB3aWxsIHVzZQogICAgdGhyZWUgdGVybXMgaW4gdGhpcyBhbmQgb25seSB0aGlzIGNvbnRleHQ6IHdpbGQtdHlwZSAod3QpLCBoZXQsIGFuZCBtdXQuCgoyLiAgVGhlIGluZGl2aWR1YWwgdHJhbnNsYXRvbWUuICBUaGVzZSBhcmUgZGVmaW5lcyBhcyBzb21ldGhpbmcgLyBiYXNlbGluZS4gIEkKICAgIHdpbGwgZXhjbHVzaXZlbHkgY2FsbCB0aGUgd3Qgc2FtcGxlcyAnYmFzZWxpbmUnIHdoZW4gc3BlYWtpbmcgaW4gdGhpcwogICAgY29udGV4dC4gIEkgd2lsbCBleGNsdXNpdmVseSBzdGF0ZSAnbm9ybWFsJyB3aGVuIHJlZmVycmluZyB0byBoZXQgLyB3dAogICAgc2FtcGxlcywgYW5kIEkgd2lsbCBzdGF0ZSAna28nIHdoZW4gcmVmZXJyaW5nIHRvIG11dCAvIHd0IHNhbXBsZXMgaW4gdGhlCiAgICB0cmFuc2xhdG9tZSBjb250ZXh0LgoKMy4gIFRyYW5zbGF0b21lIHZzLiB0cmFuc2xhdG9tZS4gIFdoZW5ldmVyIGNvbXBhcmluZyB0cmFuc2xhdG9tZXMsIEkgd2lsbCB1c2UKICAgIHRoZSBuYW1lcyBhcyBpbiAjMiBhbmQgYWx3YXlzIHB1dCB0aGUgbnVtZXJhdG9yIGZpcnN0IHdoZW4gd3JpdGluZyB0aGUgbmFtZQogICAgb2YgYSBjb21wYXJpc29uLgoKVGhlIG1vc3QgY29tcGxleCBleGFtcGxlIG9mIHRoZSBhYm92ZSBub21lbmNsYXR1cmUgaXM6Cgoibm9ybWtvX3JldGRsZ24gaXMgZGVmaW5lZCBhcyBub3JtcmV0X3ZzX25vcm1kbGduIC0ga29yZXRfdnNfa29kbGduIgoKVGhpcyBzdGF0ZXMgd2UgYXJlIGV4YW1pbmluZyBhdCB0aGUgdHJhbnNsYXRvbWUgY29udGV4dDoKICAgKG5vcm0ocmV0aW5hIHRyYW5zbGF0b21lKSAtIG5vcm0oZGxnbiB0cmFuc2xhdG9tZSkpIC0KICAgKGtvKHJldGluYSB0cmFuc2xhdG9tZSkgLSBrbyhkbGduIHRyYW5zbGF0b21lKSkKCldoaWNoIGluIHR1cm4gaXMgc3lub255bW91cyB0byB0aGUgZm9sbG93aW5nIGF0IHRoZSBzYW1wbGUgY29udGV4dDoKICAoKHJldGhldCAtIHJldHd0KSAgLSAgKGRsZ25oZXQgLSBkbGdud3QpKSAgLQogICgocmV0a28gLSByZXR3dCkgIC0gIChkbGdua28gLSBkbGdud3QpKQoKTm93IGxldCB1cyBhc3NvY2lhdGUgdGhlIHZhcmlvdXMgdmFyaWFibGUgbmFtZXMgd2l0aCB0aGUgYXBwcm9wcmlhdGUgc2FtcGxlczoKCmBgYHtyIHNhbXBsZV9uYW1lc30KZGxnbnd0IDwtICJpcHJnY18wMSIKcmV0d3QgPC0gImlwcmdjXzAyIgpzY253dCA8LSAiaXByZ2NfMDMiCgpkbGduaGV0IDwtICJpcHJnY18wNCIKcmV0aGV0IDwtICJpcHJnY18wNSIKc2NuaGV0IDwtIE5VTEwgICMjIERvZXMgbm90IHlldCBleGlzdC4KCmRsZ25tdXQgPC0gImlwcmdjXzA2IgpyZXRtdXQgPC0gImlwcmdjXzA3IgpzY25tdXQgPC0gImlwcmdjXzA4IgpgYGAKCkdpdmUgdGhlc2UgdmFyaWFibGUgbmFtZXMsIG5vdyBsZXRzIGFzc29jaWF0ZSBjb2x1bW5zIG9mIHRoZSBleHByZXNzaW9uIGRhdGEKd2l0aCB0aGVtLiAgVGhlc2UgYXJlIGF0IHRoZSBzYW1wbGUgY29udGV4dCwgc28gdGhlIGFwcHJvcHJpYXRlIG5hbWVzIGFyZToKJ3d0JywgJ2hldCcsIGFuZCAnbXV0Jy4gIEluIGVhY2ggY2FzZSBJIHdpbGwgcHJlZml4IHRoZSBnZW5vdHlwZSB3aXRoIHRoZSB0aXNzdWUKdHlwZTogJ3JldCcsICdkbGduJywgYW5kICdzY24nLiAgVGh1cyAncmV0d3QnIHJlZmVycyB0byB0aGUgc2FtcGxlIHVzZWQKdG8gY2FsY3VsYXRlIHRoZSB0cmFuc2xhdG9tZSByZXRpbmEgYmFzZWxpbmU7IGluIGNvbnRyYXN0ICdkbGdubXV0JyBpcyB0aGUKc2FtcGxlIHdoaWNoIHByb3ZpZGVzIHRoZSBkbGduIGtub2Nrb3V0LgoKYGBge3Igc2FtcGxlX2NvbHVtbnN9CiMjIFNhbXBsZSBjb250ZXh0Cm1tMzhfbm9ybSA8LSBtbV9ub3JtX3NhCmRsZ253dCA8LSBleHBycyhtbTM4X25vcm0pWywgZGxnbnd0XQpyZXR3dCA8LSBleHBycyhtbTM4X25vcm0pWywgcmV0d3RdCnNjbnd0IDwtIGV4cHJzKG1tMzhfbm9ybSlbLCBzY253dF0KZGxnbmhldCA8LSBleHBycyhtbTM4X25vcm0pWywgZGxnbmhldF0KcmV0aGV0IDwtIGV4cHJzKG1tMzhfbm9ybSlbLCByZXRoZXRdCmRsZ25tdXQgPC0gZXhwcnMobW0zOF9ub3JtKVssIGRsZ25tdXRdCnJldG11dCA8LSBleHBycyhtbTM4X25vcm0pWywgcmV0bXV0XQpzY25tdXQgPC0gZXhwcnMobW0zOF9ub3JtKVssIHNjbm11dF0KYGBgCgpFYWNoIG9mIHRoZSBhYm92ZSA4IHZhcmlhYmxlcyBwcm92aWRlcyAxIGNvbHVtbiBvZiBpbmZvcm1hdGlvbi4gV2UgaGF2ZSAzCmJhc2VsaW5lIGNvbXBhcmlzb25zIGF2YWlsYWJsZSB0byB1cy4gIEluIGVhY2ggb2YgdGhlc2Ugd2UgY29tcGFyZSBvbmUgd3QKc2FtcGxlIHRvIGFub3RoZXIuCgpgYGB7ciBiYXNlbGluZV9jb21wYXJpc29uc30KIyMgQmFzZWxpbmUgY29tcGFyaXNvbnMKd3RfZGxnbnJldCA8LSBkbGdud3QgLSByZXR3dAp3dF9zY25yZXQgPC0gc2Nud3QgLSByZXR3dAp3dF9kbGduc2NuIDwtIGRsZ253dCAtIHNjbnd0CmBgYAoKU2ltdWx0YW5lb3VzbHksIHdlIGhhdmUgNSBhdmFpbGFibGUgdHJhbnNsYXRvbWVzLiAgVGhpcyBhcmUgcHJvdmlkZWQgYnkKY29tcGFyaW5nIGVhY2ggaGV0IG9yIG11dCB0byB0aGUgYXNzb2NpYXRlZCB3dC4gIFRoZXNlIHdpbGwgdGhlcmVmb3JlIHJlY2VpdmUKbmFtZXM6ICdub3JtJyBhbmQgJ2tvJyBpbnN0ZWFkIG9mICdoZXQnIGFuZCAnbXV0Jy4KCmBgYHtyIHRyYW5zbGF0b21lc30KIyMgVHJhbnNsYXRvbWUgY29udGV4dApub3JtcmV0IDwtIHJldGhldCAtIHJldHd0CmtvcmV0IDwtIHJldG11dCAtIHJldHd0Cmtvc2NuIDwtIHNjbm11dCAtIHNjbnd0Cm5vcm1kbGduIDwtIGRsZ25oZXQgLSBkbGdud3QKa29kbGduIDwtIGRsZ25tdXQgLSBkbGdud3QKYGBgCgpHaXZlbiB0aGVzZSB0cmFuc2xhdG9tZXMsIHRoZXJlIGFyZSBhIGZldyBjb250cmFzdHMgb2YgbGlrZWx5IGludGVyZXN0LiAgVGhlc2UKYXJlIHBlcmZvcm1lZCBieSBjb21wYXJpbmcgdGhlIHJlbGV2YW50IHRyYW5zbGF0b21lcy4KCldpbGwgd2lsbCBzcGxpdCB0aGVzZSBpbnRvIDQgc2VwYXJhdGUgY2F0ZWdvcmllczoKaGV0IHZzIGhldCwga28gdnMga28sIGtvIHZzIGhldCwgYW5kIHJhdGlvIHZzIHJhdGlvLgoKRmluYWxseSwgbm90ZSB0aGF0IHdlIGFyZSBiZWluZyBleHBsaWNpdGx5IHJlZHVuZGFudCBpbiB0aGVzZSBkZWZpbml0aW9ucy4gIEkgYW0KbWFraW5nIHZhcmlhYmxlIG5hbWVzIGZvciBib3RoIHRoZSBhL2IgcmF0aW8gYW5kIHRoZSBiL2EgcmF0aW8uICBUaHVzIHdlIGhhdmUKc29tZSByZWR1bmRhbnRseSByZWR1bmRhbnQgKGhhaGEpIGZsZXhpYmlsaXR5IHdoZW4gZGVjaWRpbmcgb24gd2hhdCB3ZSB3YW50IHRvIHBsb3QuCgpgYGB7ciBub3JtX3ZzX25vcm19CiMjIG5vcm0gdnMgbm9ybQpub3JtZGxnbl92c19ub3JtcmV0IDwtIG5vcm1kbGduIC0gbm9ybXJldApub3JtcmV0X3ZzX25vcm1kbGduIDwtIG5vcm1yZXQgLSBub3JtZGxnbgpgYGAKCmBgYHtyIGtvX3ZzX2tvfQojIyBrbyB2cyBrbwprb3JldF92c19rb2RsZ24gPC0ga29yZXQgLSBrb2RsZ24Ka29kbGduX3ZzX2tvcmV0IDwtIGtvZGxnbiAtIGtvcmV0Cgprb3JldF92c19rb3NjbiA8LSBrb3JldCAtIGtvc2NuCmtvc2NuX3ZzX2tvcmV0IDwtIGtvc2NuIC0ga29yZXQKCmtvZGxnbl92c19rb3NjbiA8LSBrb2RsZ24gLSBrb3Njbgprb3Njbl92c19rb2RsZ24gPC0ga29zY24gLSBrb2RsZ24KYGBgCgpPbiB0aGUgb3RoZXIgaGFuZCwgSSBhbSBhc3N1bWluZyB3ZSBhbHdheXMgd2FudCB0aGUgbm9ybWFscyBhcyBkZW5vbWluYXRvcnMgYW5kCmtvcyBhcyBudW1lcmF0b3JzLgoKYGBge3Iga29fdnNfbm9ybX0KIyMga28gdnMgbm9ybQprb3JldF92c19ub3JtcmV0IDwtIGtvcmV0IC0gbm9ybXJldAoKa29kbGduX3ZzX25vcm1kbGduIDwtIGtvZGxnbiAtIG5vcm1kbGduCmBgYAoKRmluYWxseSwgaGVyZSBpcyB0aGUgcmF0aW8gb2YgcmF0aW9zIGV4YW1wbGUgSSBwcmludGVkIGFib3ZlOgoKSSBuYW1lZCBpdCAnbm9ybWtvX3JldGRsZ24nIGluIGFuIGF0dGVtcHQgdG8gbWFrZSBjbGVhciB0aGF0IGl0IGlzIGFjdHVhbGx5OgogKG5vcm1yZXQvbm9ybWRsZ24pLyhrb3JldC9rb2RsZ24pCgpvciBzdGF0ZWQgZGlmZmVyZW50bHk6ICJub3JtIGRpdmlkZWQgYnkga28gZm9yIHJldCBkaXZpZGVkIGJ5IGRsZ24uIgoKYGBge3Igcm9yfQojIyByYXRpbyBvZiByYXRpb3MKbm9ybWtvX3JldGRsZ24gPC0gbm9ybXJldF92c19ub3JtZGxnbiAtIGtvcmV0X3ZzX2tvZGxnbgpgYGAKCiMjIERlZmluZSBhIG1hdHJpeCBvZiB0aGVzZSB2YWx1ZXMuCgpNeSBtYXRyaXggb2YgZGF0YSB3aWxsIG5vdyBjb250YWluIDEgY29sdW1uIGZvciBlYWNoIG9mIHRoZSBhYm92ZSAyNwpzYW1wbGVzL2NvbXBhcmlzb25zLgoKYGBge3IgbWF0cml4X29mX3ZhbHVlc30KcGFpcl9tdHJ4IDwtIGNiaW5kKAogICMjIEluZGl2aWR1YWwgc2FtcGxlcwogIGRsZ253dCwgcmV0d3QsIHNjbnd0LCBkbGduaGV0LCByZXRoZXQsIGRsZ25tdXQsIHJldG11dCwgc2NubXV0LAogICMjIEJhc2VsaW5lIGNvbXBhcmlzb25zCiAgd3RfZGxnbnJldCwgd3Rfc2NucmV0LCB3dF9kbGduc2NuLAogICMjIEJhc2VsaW5lIHN1YnRyYWN0aW9ucwogIG5vcm1kbGduLCBub3JtcmV0LCBrb2RsZ24sIGtvcmV0LCBrb3NjbiwKICAjIyBoZXRfdnNfaGV0LCBvZiB3aGljaCB0aGVyZSBpcyBvbmx5IDEgYmVjYXVzZSB3ZSBkbyBub3QgaGF2ZSBoZXRzY24KICBub3JtZGxnbl92c19ub3JtcmV0LCBub3JtcmV0X3ZzX25vcm1kbGduLAogICMjIGtvX3ZzX2tvLCBvZiB3aGljaCB3ZSBoYXZlIDMKICBrb3JldF92c19rb2RsZ24sIGtvZGxnbl92c19rb3JldCwKICBrb3JldF92c19rb3Njbiwga29zY25fdnNfa29yZXQsCiAga29kbGduX3ZzX2tvc2NuLCBrb3Njbl92c19rb2RsZ24sCiAgIyMga29fdnNfaGV0LCAzIGluY2x1ZGluZyBvbmUgZ2V0dGluZyBhcm91bmQgbWlzc2luZyBoZXRzY24KICBrb3JldF92c19ub3JtcmV0LCBrb2RsZ25fdnNfbm9ybWRsZ24sCiAgIyMgcmF0aW8gb2YgcmF0aW9zCiAgbm9ybWtvX3JldGRsZ24pCmBgYAoKIyMgQ3V0b2ZmcwoKSSBhbSBub3Qgc3VyZSBpZiB3ZSB3aWxsIHVzZSB0aGVzZSBpbmRleGVzLCBidXQgSSBhbSB3cml0aW5nIHRoZXNlIG91dCBhcwpzdWJzZXRzIG9mIGdlbmVzIHRvIGxvb2sgYXQuICBUaGVzZSBpbmRleGVzIGFyZSBzdGF0aW5nIHRoYXQsIGdpdmVuIGEgY3V0b2ZmCigwKSwgd2Ugd2FudCB0byBsb29rIGF0IG9ubHkgdGhlIGdlbmVzIHdoaWNoIGhhdmUgaGlnaGVyIHggLyBiYXNlbGluZSB2YWx1ZXMKdGhhbiB0aGUgY3V0b2ZmLgoKCmBgYHtyIGN1dG9mZnN9CiMjIFF1ZXJpZXMgYWJvdXQgZ2VuZSBzdWJzZXRzLgojIyBUaGVzZSBhcmUgYWxsIGluIHRoZSBjb250ZXh0IG9mIHRyYW5zbGF0b21lcy4KY3V0b2ZmIDwtIDAKcmV0X2tlcHRfaWR4IDwtIG5vcm1yZXQgPiBjdXRvZmYgJiBrb3JldCA+IGN1dG9mZgpzY25fa2VwdF9pZHggPC0ga29zY24gPiBjdXRvZmYKZGxnbl9rZXB0X2lkeCA8LSBub3JtZGxnbiA+IGN1dG9mZiAmIGtvZGxnbiA+IGN1dG9mZgpyZXRfZGxnbl9rZXB0X2lkeCA8LSByZXRfa2VwdF9pZHggJiBkbGduX2tlcHRfaWR4CnJldF9zY25fa2VwdF9pZHggPC0gcmV0X2tlcHRfaWR4ICYgc2NuX2tlcHRfaWR4CmRsZ25fc2NuX2tlcHRfaWR4IDwtIGRsZ25fa2VwdF9pZHggJiBzY25fa2VwdF9pZHgKCiMjbm9ybWRsZ25fdnNfbm9ybXJldFshcmV0X2RsZ25fa2VwdF9pZHhdIDwtIE5BCiMjbm9ybXJldF92c19ub3JtZGxnblshcmV0X2RsZ25fa2VwdF9pZHhdIDwtIE5BCiMja29yZXRfdnNfa29kbGduWyFyZXRfZGxnbl9rZXB0X2lkeF0gPC0gTkEKIyNrb2RsZ25fdnNfa29yZXRbIXJldF9kbGduX2tlcHRfaWR4XSA8LSBOQQojI2tvcmV0X3ZzX2tvc2NuWyFyZXRfc2NuX2tlcHRfaWR4XSA8LSBOQQojI2tvc2NuX3ZzX2tvcmV0WyFyZXRfc2NuX2tlcHRfaWR4XSA8LSBOQQojI2tvZGxnbl92c19rb3NjblshZGxnbl9zY25fa2VwdF9pZHhdIDwtIE5BCiMja29zY25fdnNfa29kbGduWyFkbGduX3Njbl9rZXB0X2lkeF0gPC0gTkEKIyNrb3JldF92c19ub3JtcmV0WyFyZXRfa2VwdF9pZHhdIDwtIE5BCiMja29kbGduX3ZzX25vcm1kbGduWyFkbGduX2tlcHRfaWR4XSA8LSBOQQojI25vcm1rb19yZXRkbGduIDwtIG5vcm1rb19yZXRkbGduWyFyZXRfZGxnbl9rZXB0X2lkeF0gPC0gTkEKYGBgCgojIyBBZGQgdGhlIG1hdHJpeCB0byB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24KCkkgd2lsbCB1c2UgbXkgZnVuY3Rpb24gY29tYmluZV9kZV90YWJsZXMoKSB0byBhZGQgdGhpcyBpbmZvcm1hdGlvbiB0byBteQpleGlzdGluZyBhbm5vdGF0aW9uIGRhdGEgYWxvbmcgd2l0aCB0aGUgcmVzdWx0cyBmcm9tIHRoZSBzdGF0aXN0aWNhbGx5IHZhbGlkCmNvbXBhcmlzb24gb2YgdGhlIHRocmVlIHRpc3N1ZSB0eXBlcy4KCmBgYHtyIGFkZF9tYXRyaXhfZGUsIGZpZy5zaG93PSJoaWRlIiwgZXZhbD1GQUxTRX0KbW1fdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX2RlX3NhLCBleHRyYV9hbm5vdD1wYWlyX210cngsCiAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9bW1fc2FsbW9uX3RhYmxlcy12e3Zlcn0ueGxzeCIpKSkKYGBgCgojIFBsb3RzIG9mIGludGVyZXN0aW5nIGNvbXBhcmlzb25zCgojIyBSZXRpbmEsIGhldCB2cy4gd3QuCgpgYGB7ciByZXRfaGV0d3RfcGxvdCwgZXZhbD1GQUxTRX0KIyMgUHV0IHJldGluYSBiYXNlbGluZSBvbiB5IGF4aXMgYXMgYmxhY2ssIHJldGluYSBoZXQgb24geCBheGlzIGFzIGJsYWNrLgojIyBUaGVuIHJlY29sb3IgYSBzdWJzZXQgb2YgdGhlc2UgYXMgcmVkLCB0aGUgcmVkcyBhcmUgd2hlbiBub3JtcmV0ID4gMApsaWJyYXJ5KGdncGxvdDIpCgpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygicmV0aGV0IiwgInJldHd0IildKQpyZWRfaWR4IDwtIG5vcm1yZXQgPiAwCnBsb3R0ZWRbLCAiY29sb3IiXSA8LSBpZmVsc2UocmVkX2lkeCwgInJlZCIsICJibGFjayIpCnBsb3R0ZWRbWyJsYWJlbCJdXSA8LSByb3duYW1lcyhwbG90dGVkKQpyZXRfaGV0d3QgPC0gZ2dwbG90KAogIHBsb3R0ZWQsCiAgYWVzX3N0cmluZyh4PSJyZXRoZXQiLCB5PSJyZXR3dCIsIGxhYmVsPSJsYWJlbCIsIGNvbG9yPSJjb2xvciIpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwgInJlZCIpKQpyZXRfaGV0d3QKcmV0X2hldHd0X2NsaWNreSA8LSBnZ3Bsb3RseV91cmwoCiAgcmV0X2hldHd0LCAicmV0X2hldHd0Lmh0bWwiLCB0aXRsZT0iUmV0aW5hIGV4cHJlc3Npb24sIGhldCB2cy4gd3QuIiwKICB1cmxfZGF0YT0iaHR0cDovL3VzZWFzdC5lbnNlbWJsLm9yZy9NdXNfbXVzY3VsdXMvR2VuZS9TdW1tYXJ5P2c9e2lkc30iKQpgYGAKCiMjIFJldGluYSwgbXV0IHZzIHd0LgoKYGBge3IgcmV0X2hldG11dF9wbG90LCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygicmV0bXV0IiwgInJldHd0IildKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKcGxvdHRlZFtbImNvbG9yIl1dIDwtICJibGFjayIKcmV0X211dHd0IDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0icmV0bXV0IiwgeT0icmV0d3QiLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKcmV0X211dHd0CnJldF9tdXR3dF9jbGlja3kgPC0gZ2dwbG90bHlfdXJsKAogIHJldF9tdXR3dCwgInJldF9tdXR3dC5odG1sIiwgdGl0bGU9IlJldGluYSBleHByZXNzaW9uLCBtdXRhbnQgdnMuIHd0LiIsCiAgdXJsX2RhdGE9Imh0dHA6Ly91c2Vhc3QuZW5zZW1ibC5vcmcvTXVzX211c2N1bHVzL0dlbmUvU3VtbWFyeT9nPXtpZHN9IikKYGBgCgojIyBkbGduLCBoZXQgdnMuIHd0LgoKYGBge3IgZGxnbl9oZXRfd3RfcGxvdCwgZXZhbD1GQUxTRX0KcGxvdHRlZCA8LSBhcy5kYXRhLmZyYW1lKHBhaXJfbXRyeFssIGMoImRsZ25oZXQiLCAiZGxnbnd0IildKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKcGxvdHRlZFtbImNvbG9yIl1dIDwtICJibGFjayIKZGxnbl9oZXR3dCA8LSBnZ3Bsb3QoCiAgcGxvdHRlZCwKICBhZXNfc3RyaW5nKHg9ImRsZ25oZXQiLCB5PSJkbGdud3QiLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKZGxnbl9oZXR3dApkbGduX2hldHd0X2NsaWNreSA8LSBnZ3Bsb3RseV91cmwoCiAgZGxnbl9oZXR3dCwgImRsZ25faGV0d3QuaHRtbCIsIHRpdGxlPSJkbGduIGV4cHJlc3Npb24sIGhldCB2cy4gd3QuIiwKICB1cmxfZGF0YT0iaHR0cDovL3VzZWFzdC5lbnNlbWJsLm9yZy9NdXNfbXVzY3VsdXMvR2VuZS9TdW1tYXJ5P2c9e2lkc30iKQpgYGAKCiMjIGRsZ24sIG11dCB2cy4gd3QuCgpgYGB7ciBkbGduX211dF93dF9wbG90LCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygiZGxnbm11dCIsICJkbGdud3QiKV0pCnBsb3R0ZWRbWyJsYWJlbCJdXSA8LSByb3duYW1lcyhwbG90dGVkKQpwbG90dGVkW1siY29sb3IiXV0gPC0gImJsYWNrIgpkbGduX211dHd0IDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0iZGxnbm11dCIsIHk9ImRsZ253dCIsIGxhYmVsPSJsYWJlbCIsIGNvbG9yPSJjb2xvciIpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwgInJlZCIpKQpkbGduX211dHd0CmRsZ25fbXV0d3RfY2xpY2t5IDwtIGdncGxvdGx5X3VybCgKICBkbGduX211dHd0LCAiZGxnbl9tdXR3dC5odG1sIiwgdGl0bGU9ImRsZ24gZXhwcmVzc2lvbiwgbXV0IHZzLiB3dC4iLAogIHVybF9kYXRhPSJodHRwOi8vdXNlYXN0LmVuc2VtYmwub3JnL011c19tdXNjdWx1cy9HZW5lL1N1bW1hcnk/Zz17aWRzfSIpCmBgYAoKIyMgc2NuLCBtdXQgdnMuIHd0LgoKYGBge3Igc2NuX211dF93dF9wbG90LCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygic2NubXV0IiwgInNjbnd0IildKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKcGxvdHRlZFtbImNvbG9yIl1dIDwtICJibGFjayIKc2NuX211dHd0IDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0ic2NubXV0IiwgeT0ic2Nud3QiLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKc2NuX211dHd0CnNjbl9tdXR3dF9jbGlja3kgPC0gZ2dwbG90bHlfdXJsKAogIHNjbl9tdXR3dCwgInNjbl9tdXR3dC5odG1sIiwgdGl0bGU9InNjbiBleHByZXNzaW9uLCBtdXQgdnMuIHd0LiIsCiAgdXJsX2RhdGE9Imh0dHA6Ly91c2Vhc3QuZW5zZW1ibC5vcmcvTXVzX211c2N1bHVzL0dlbmUvU3VtbWFyeT9nPXtpZHN9IikKYGBgCgojIyBBeG9uIHRyYW5zbGF0b21lIHNwZWNpZmljCgpgYGB7ciBheG9uX3RyYW5zbGF0b21lX3Bsb3QsIGV2YWw9RkFMU0V9CiMjICB4LWF4aXM6IG5vcm1kbGduX3ZzX25vcm1yZXQgb3Igbm9ybXJldF92c19ub3JtZGxnbiwKIyMgICAgICAgICAgICAgIF5eXl4KIyMgIHktYXhpczogZGxnbnd0LXJldHd0IChiYXNlbGluZSBkbGduIC0gYmFzZWxpbmUgcmV0aW5hKQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygibm9ybWRsZ25fdnNfbm9ybXJldCIsICJ3dF9kbGducmV0IildKQpyZWRfaWR4IDwtIG5vcm1yZXQgPiAwCiMjIE5vdGUgdGhhdCB0aGlzIG9yZGVyIGlzIG9wcG9zaXRlIG9mIGFib3ZlLgpwbG90dGVkWywgImNvbG9yIl0gPC0gaWZlbHNlKHJlZF9pZHgsICJibGFjayIsICJyZWQiKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKYXhvbl90cmFuc19yZXRfdGFyZ2V0IDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0ibm9ybWRsZ25fdnNfbm9ybXJldCIsIHk9Ind0X2RsZ25yZXQiLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKYXhvbl90cmFuc19yZXRfdGFyZ2V0CmF4b25fdHJhbnNfcmV0X3RhcmdldF9jbGlja3kgPC0gZ2dwbG90bHlfdXJsKAogIGF4b25fdHJhbnNfcmV0X3RhcmdldCwgImF4b25fdHJhbnNfcmV0X3RhcmdldC5odG1sIiwgdGl0bGU9IkF4b24gdHJhbnNsYXRvbWUsIHJldGluYSB0YXJnZXQuIiwKICB1cmxfZGF0YT0iaHR0cDovL3VzZWFzdC5lbnNlbWJsLm9yZy9NdXNfbXVzY3VsdXMvR2VuZS9TdW1tYXJ5P2c9e2lkc30iKQpgYGAKCiMjIERMR04gdHJhbnNsYXRvbWUgd3J0LiBSZXRpbmEgdHJhbnNsYXRvbWUKCmBgYHtyIGRsZ25fdHJhbnNsYXRvbWVfcGxvdCwgZXZhbD1GQUxTRX0KcGxvdHRlZCA8LSBhcy5kYXRhLmZyYW1lKHBhaXJfbXRyeFssIGMoIm5vcm1yZXQiLCAibm9ybWRsZ24iKV0pCnBsb3R0ZWRbWyJsYWJlbCJdXSA8LSByb3duYW1lcyhwbG90dGVkKQpwbG90dGVkW1siY29sb3IiXV0gPC0gImJsYWNrIgpub3JtcmV0X25vcm1kbGduIDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0ibm9ybXJldCIsIHk9Im5vcm1kbGduIiwgbGFiZWw9ImxhYmVsIiwgY29sb3I9ImNvbG9yIikpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCAicmVkIikpCm5vcm1yZXRfbm9ybWRsZ24Kbm9ybXJldF9ub3JtZGxnbl9jbGlja3kgPC0gZ2dwbG90bHlfdXJsKAogIG5vcm1yZXRfbm9ybWRsZ24sICJub3JtcmV0X25vcm1kbGduLmh0bWwiLCB0aXRsZT0iTm9ybWFsIHJldGluYSB0cmFuc2xhdG9tZSB2cyBub3JtYWwgZGxnbiB0cmFuc2xhdG9tZS4iLAogIHVybF9kYXRhPSJodHRwOi8vdXNlYXN0LmVuc2VtYmwub3JnL011c19tdXNjdWx1cy9HZW5lL1N1bW1hcnk/Zz17aWRzfSIpCmBgYAoKIyMga29yZXQga29kbGduCgpgYGB7ciBrb3JldF9rb2RsZ25fc29tZXRoaW5nc29tZXRoaW5ncGxvdCwgZXZhbD1GQUxTRX0KcGxvdHRlZCA8LSBhcy5kYXRhLmZyYW1lKHBhaXJfbXRyeFssIGMoImtvcmV0IiwgImtvZGxnbiIpXSkKcGxvdHRlZFtbImxhYmVsIl1dIDwtIHJvd25hbWVzKHBsb3R0ZWQpCnBsb3R0ZWRbWyJjb2xvciJdXSA8LSAiYmxhY2siCmtvcmV0X2tvZGxnbiA8LSBnZ3Bsb3QoCiAgcGxvdHRlZCwKICBhZXNfc3RyaW5nKHg9ImtvcmV0IiwgeT0ia29kbGduIiwgbGFiZWw9ImxhYmVsIiwgY29sb3I9ImNvbG9yIikpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCAicmVkIikpCmtvcmV0X2tvZGxnbgprb3JldF9rb2RsZ25fY2xpY2t5IDwtIGdncGxvdGx5X3VybCgKICBrb3JldF9rb2RsZ24sICJrb3JldF9rb2RsZ24uaHRtbCIsIHRpdGxlPSJLTyByZXRpbmEgdHJhbnNsYXRvbWUgdnMgS08gZGxnbiB0cmFuc2xhdG9tZS4iLAogIHVybF9kYXRhPSJodHRwOi8vdXNlYXN0LmVuc2VtYmwub3JnL011c19tdXNjdWx1cy9HZW5lL1N1bW1hcnk/Zz17aWRzfSIpCmBgYAoKIyMgS08gUmV0aW5hIHZzIEtPIFNDTgoKYGBge3Iga29yZXRfa29zY25fcGxvdF9yYXdyLCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygia29yZXQiLCAia29zY24iKV0pCnBsb3R0ZWRbWyJsYWJlbCJdXSA8LSByb3duYW1lcyhwbG90dGVkKQpwbG90dGVkW1siY29sb3IiXV0gPC0gImJsYWNrIgprb3JldF9rb3NjbiA8LSBnZ3Bsb3QoCiAgcGxvdHRlZCwKICBhZXNfc3RyaW5nKHg9ImtvcmV0IiwgeT0ia29zY24iLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKa29yZXRfa29zY24Ka29yZXRfa29zY25fY2xpY2t5IDwtIGdncGxvdGx5X3VybCgKICBrb3JldF9rb3NjbiwgImtvcmV0X2tvc2NuLmh0bWwiLCB0aXRsZT0iS08gcmV0aW5hIHRyYW5zbGF0b21lIHZzIEtPIHNjbiB0cmFuc2xhdG9tZS4iLAogIHVybF9kYXRhPSJodHRwOi8vdXNlYXN0LmVuc2VtYmwub3JnL011c19tdXNjdWx1cy9HZW5lL1N1bW1hcnk/Zz17aWRzfSIpCmBgYAoKIyMgTm9ybSBkbGduIGtvIGRsZ24KCmBgYHtyIG5vcm1kbGduX2tvZGxnbl9wbG90LCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygibm9ybWRsZ24iLCAia29kbGduIildKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKcGxvdHRlZFtbImNvbG9yIl1dIDwtICJibGFjayIKbm9ybWRsZ25fa29kbGduIDwtIGdncGxvdCgKICBwbG90dGVkLAogIGFlc19zdHJpbmcoeD0ibm9ybWRsZ24iLCB5PSJrb2RsZ24iLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKbm9ybWRsZ25fa29kbGduCm5vcm1kbGduX2tvZGxnbl9jbGlja3kgPC0gZ2dwbG90bHlfdXJsKAogIG5vcm1kbGduX2tvZGxnbiwgIm5vcm1kbGduX2tvZGxnbi5odG1sIiwgdGl0bGU9Ik5vcm1hbCBkbGduIHRyYW5zbGF0b21lIHZzIEtPIGRsZ24gdHJhbnNsYXRvbWUuIiwKICB1cmxfZGF0YT0iaHR0cDovL3VzZWFzdC5lbnNlbWJsLm9yZy9NdXNfbXVzY3VsdXMvR2VuZS9TdW1tYXJ5P2c9e2lkc30iKQpgYGAKCiMjIE5vcm0gcmV0IHZzIGtvIHJldAoKYGBge3Igbm9ybV9yZXRfa29fcmV0X3Bsb3QsIGV2YWw9RkFMU0V9CnBsb3R0ZWQgPC0gYXMuZGF0YS5mcmFtZShwYWlyX210cnhbLCBjKCJub3JtcmV0IiwgImtvcmV0IildKQpwbG90dGVkW1sibGFiZWwiXV0gPC0gcm93bmFtZXMocGxvdHRlZCkKcGxvdHRlZFtbImNvbG9yIl1dIDwtICJibGFjayIKbm9ybXJldF9rb3JldCA8LSBnZ3Bsb3QoCiAgcGxvdHRlZCwKICBhZXNfc3RyaW5nKHg9Im5vcm1yZXQiLCB5PSJrb3JldCIsIGxhYmVsPSJsYWJlbCIsIGNvbG9yPSJjb2xvciIpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwgInJlZCIpKQpub3JtcmV0X2tvcmV0Cm5vcm1yZXRfa29yZXRfY2xpY2t5IDwtIGdncGxvdGx5X3VybCgKICBub3JtcmV0X2tvcmV0LCAibm9ybXJldF9rb3JldC5odG1sIiwgdGl0bGU9Ik5vcm1hbCByZXRpbmEgdHJhbnNsYXRvbWUgdnMgS08gcmV0aW5hIHRyYW5zbGF0b21lLiIsCiAgdXJsX2RhdGE9Imh0dHA6Ly91c2Vhc3QuZW5zZW1ibC5vcmcvTXVzX211c2N1bHVzL0dlbmUvU3VtbWFyeT9nPXtpZHN9IikKYGBgCgojIyByb3IKCmBgYHtyIHJvcl9wbG90LCBldmFsPUZBTFNFfQpwbG90dGVkIDwtIGFzLmRhdGEuZnJhbWUocGFpcl9tdHJ4WywgYygibm9ybXJldF92c19ub3JtZGxnbiIsICJrb3JldF92c19rb2RsZ24iKV0pCnBsb3R0ZWRbWyJsYWJlbCJdXSA8LSByb3duYW1lcyhwbG90dGVkKQpwbG90dGVkW1siY29sb3IiXV0gPC0gImJsYWNrIgpub3JtYWxfa29fYXhvbl90cmFuc2xhdG9tZSA8LSBnZ3Bsb3QoCiAgcGxvdHRlZCwKICBhZXNfc3RyaW5nKHg9Im5vcm1yZXRfdnNfbm9ybWRsZ24iLCB5PSJrb3JldF92c19rb2RsZ24iLCBsYWJlbD0ibGFiZWwiLCBjb2xvcj0iY29sb3IiKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJyZWQiKSkKbm9ybWFsX2tvX2F4b25fdHJhbnNsYXRvbWUKbm9ybWFsX2tvX2F4b25fdHJhbnNsYXRvbWVfY2xpY2t5IDwtIGdncGxvdGx5X3VybCgKICBub3JtYWxfa29fYXhvbl90cmFuc2xhdG9tZSwgIm5vcm1hbF9rb19heG9uX3RyYW5zbGF0b21lLmh0bWwiLAogIHRpdGxlPSJOb3JtYWwgcmV0aW5hIGtvIGF4b24gdHJhbnNsYXRvbWUuIiwKICB1cmxfZGF0YT0iaHR0cDovL3VzZWFzdC5lbnNlbWJsLm9yZy9NdXNfbXVzY3VsdXMvR2VuZS9TdW1tYXJ5P2c9e2lkc30iKQpgYGAKCiMgVHJhbnNsYXRvbWUgbGV2ZWwgY29tcGFyaXNvbnMKCiMjIE1ha2UgYSBnZW5lcmljIHBsb3R0ZXIgZm9yIHRoaXMgc3R1ZmYuCgpgYGB7ciBnZW5lcmljX3Bsb3R0ZXIsIGV2YWw9RkFMU0V9CnRyYW5zbGF0b21lX3Bsb3R0ZXIgPC0gZnVuY3Rpb24ocGFpcl9tdHJ4LCB4X2F4aXM9ImtvcmV0IiwgeV9heGlzPSJrb3NjbiIsIGxmYz1OVUxMLCBmYz1OVUxMLCBsaW5ld2lkdGg9MS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwX2NvbG9yPSJyZWQiLCBkb3duX2NvbG9yPSIjMDk4NTM0IiwgbGluZV9jb2xvcj0iI2ZjYmEwMyIsIGFscGhhPTAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4X2xpbWl0PWMoLTcsIDcpLCB5X2xpbWl0PWMoLTcsIDcpKSB7CiAgaWYgKGlzLm51bGwoZmMpICYgaXMubnVsbChsZmMpKSB7CiAgICBtZXNzYWdlKCJObyBmYy9sZmMgd2FzIHByb3ZpZGVkLCBkZWZhdWx0aW5nIHRvIDEwIGZvbGQuIikKICAgIGxmYyA8LSBsb2cyKDEwKQogIH0gZWxzZSBpZiAoaXMubnVsbChsZmMpKSB7CiAgICBsZmMgPC0gbG9nMihmYykKICB9CiAgcGxvdHRlZCA8LSBhcy5kYXRhLmZyYW1lKHBhaXJfbXRyeFssIGMoeF9heGlzLCB5X2F4aXMpXSkKICBuYV9pZHggPC0gaXMubmEocGxvdHRlZCkKICBwbG90dGVkW25hX2lkeF0gPC0gMAogIHVwX2lkeCA8LSBwbG90dGVkWywgeV9heGlzXSAtIHBsb3R0ZWRbLCB4X2F4aXNdID49IGxmYwogIGRvd25faWR4IDwtIHBsb3R0ZWRbLCB5X2F4aXNdIC0gcGxvdHRlZFssIHhfYXhpc10gPD0gKGxmYyAqIC0xKQogIHVwX2dlbmVzIDwtIHJvd25hbWVzKHBsb3R0ZWQpW3VwX2lkeF0KICBkb3duX2dlbmVzIDwtIHJvd25hbWVzKHBsb3R0ZWQpW2Rvd25faWR4XQogICMjIE5vdGUgdGhhdCB0aGlzIG9yZGVyIGlzIG9wcG9zaXRlIG9mIGFib3ZlLgogIHBsb3R0ZWRbWyJjb2xvciJdXSA8LSAiYmxhY2siCiAgcGxvdHRlZFt1cF9pZHgsICJjb2xvciJdIDwtIHVwX2NvbG9yCiAgcGxvdHRlZFtkb3duX2lkeCwgImNvbG9yIl0gPC0gZG93bl9jb2xvcgogIHBsb3R0ZWRbWyJjb2xvciJdXSA8LSBhcy5mYWN0b3IocGxvdHRlZFtbImNvbG9yIl1dKQogIGxldmVscyhwbG90dGVkW1siY29sb3IiXV0pIDwtIGMoImJsYWNrIiwgdXBfY29sb3IsIGRvd25fY29sb3IpCiAgcGx0IDwtIGdncGxvdDI6OmdncGxvdChwbG90dGVkLCBhZXNfc3RyaW5nKHg9eF9heGlzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PXlfYXhpcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9ImNvbG9yIikpICsKICAgIGdlb21fYWJsaW5lKHNpemU9MS4xLCBzbG9wZT0xLCBpbnRlcmNlcHQ9bGZjLCBjb2xvcj0ib3JhbmdlIikgKwogICAgZ2VvbV9hYmxpbmUoc2l6ZT0xLjEsIHNsb3BlPTEsIGludGVyY2VwdD0oLTEgKiBsZmMpLCBjb2xvcj0ib3JhbmdlIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKHhfbGltaXQpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoeV9saW1pdCkpICsKICAgIGdlb21fcG9pbnQoYWxwaGE9YWxwaGEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Yyhkb3duX2NvbG9yLCAiYmxhY2siLCB1cF9jb2xvcikpCiAgcmV0bGlzdCA8LSBsaXN0KAogICAgIm10cngiID0gcGxvdHRlZCwKICAgICJ1cHMiID0gdXBfZ2VuZXMsCiAgICAiZG93bnMiID0gZG93bl9nZW5lcywKICAgICJwbG90IiA9IHBsdCkKICByZXR1cm4ocmV0bGlzdCkKfQpgYGAKCjEuIFgtYXhpczogQWx3YXlzIHJldGluYS4KMi4gWS1heGlzOiBBbHdheXMgYSB0YXJnZXQgdGlzc3VlLgoKRmlyc3QgcGxvdDogS08gc2NuIHRyYW5zbGF0b21lIG9uIHkgYXhpcyB2cy4gS08gcmV0aW5hIHRyYW5zbGF0b21lIG9uIHggYXhpcy4KCiMjIFNjbiBrbm9ja291dCB0cmFuc2xhdG9tZSB2cyByZXRpbmEga25vY2tvdXQgdHJhbnNsYXRvbWUuCgpgYGB7ciBzY25fa29fd3J0X3JldGluYV9rb190cmFuc2xhdG9tZV9ncHJvZmlsZXIsIGV2YWw9RkFMU0V9CnNjbmtvX3dydF9yZXRrb190cmFuc2xhdG9tZSA8LSB0cmFuc2xhdG9tZV9wbG90dGVyKHBhaXJfbXRyeCkKc2Nua29fd3J0X3JldGtvX3RyYW5zbGF0b21lJHBsb3QKc2Nua29fd3J0X3JldGtvX3VwX2dvIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzPXNjbmtvX3dydF9yZXRrb190cmFuc2xhdG9tZSR1cHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9Im1tdXNjdWx1cyIpCnNjbmtvX3dydF9yZXRrb19kb3duX2dvIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzPXNjbmtvX3dydF9yZXRrb190cmFuc2xhdG9tZSRkb3ducywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzPSJtbXVzY3VsdXMiKQpzY25rb193cnRfcmV0a29fZG93bl9nbyRnbwpzY25rb193cnRfcmV0a29fZG93bl9nbyRrZWdnCnNjbmtvX3dydF9yZXRrb19kb3duX2dvJGNvcnVtCmBgYAoKIyMgZGxnbiBub3JtYWwgdHJhbnNsYXRvbWUgdnMgcmV0aW5hIG5vcm1hbCB0cmFuc2xhdG9tZS4KCmBgYHtyIGRsZ25fbm9ybV90cmFuc2xhdG9tZV92c19yZXRfbm9ybWFsX3RyYW5zbGF0b21lX2dwcm9maWxlciwgZXZhbD1GQUxTRX0KZGxnbm5vcm1fd3J0X3JldG5vcm1fdHJhbnNsYXRvbWUgPC0gdHJhbnNsYXRvbWVfcGxvdHRlcihwYWlyX210cngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeF9heGlzPSJub3JtcmV0IiwgeV9heGlzPSJub3JtZGxnbiIpCmRsZ25ub3JtX3dydF9yZXRub3JtX3RyYW5zbGF0b21lJHBsb3QKZGxnbm5vcm1fd3J0X3JldG5vcm1fdXBfZ28gPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9ZGxnbm5vcm1fd3J0X3JldG5vcm1fdHJhbnNsYXRvbWUkdXBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9Im1tdXNjdWx1cyIpCmRsZ25ub3JtX3dydF9yZXRub3JtX2Rvd25fZ28gPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9ZGxnbm5vcm1fd3J0X3JldG5vcm1fdHJhbnNsYXRvbWUkZG93bnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzPSJtbXVzY3VsdXMiKQpkbGdubm9ybV93cnRfcmV0bm9ybV9kb3duX2dvJGdvCmRsZ25ub3JtX3dydF9yZXRub3JtX2Rvd25fZ28kcHZhbHVlX3Bsb3RzJGJwcF9wbG90X292ZXIKZGxnbm5vcm1fd3J0X3JldG5vcm1fZG93bl9nbyRwdmFsdWVfcGxvdHMkY2NwX3Bsb3Rfb3ZlcgpgYGAKCiMjIGRsZ24ga25vY2tvdXQgdHJhbnNsYXRvbWUgdnMgcmV0aW5hIGtub2Nrb3V0IHRyYW5zbGF0b21lLgoKYGBge3IgZGxnbl9rb190cmFuc2xhdG9tZV92c19yZXRpbmFfa29fdHJhbnNsYXRvbWVfZ3Byb2ZpbGVyLCBldmFsPUZBTFNFfQpkbGdua29fd3J0X3JldGtvX3RyYW5zbGF0b21lIDwtIHRyYW5zbGF0b21lX3Bsb3R0ZXIocGFpcl9tdHJ4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeF9heGlzPSJrb3JldCIsIHlfYXhpcz0ia29kbGduIikKZGxnbmtvX3dydF9yZXRrb190cmFuc2xhdG9tZSRwbG90CmRsZ25rb193cnRfcmV0a29fdXBfZ28gPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9ZGxnbmtvX3dydF9yZXRrb190cmFuc2xhdG9tZSR1cHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzPSJtbXVzY3VsdXMiKQpkbGdua29fd3J0X3JldGtvX3VwX2dvJGdvCmRsZ25rb193cnRfcmV0a29fdXBfZ28ka2VnZwpkbGdua29fd3J0X3JldGtvX3VwX2dvJHJlYWMKZGxnbmtvX3dydF9yZXRrb19kb3duX2dvIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzPWRsZ25rb193cnRfcmV0a29fdHJhbnNsYXRvbWUkZG93bnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9Im1tdXNjdWx1cyIpCmRsZ25rb193cnRfcmV0a29fZG93bl9nbyRnbwpkbGdua29fd3J0X3JldGtvX2Rvd25fZ28ka2VnZwpkbGdua29fd3J0X3JldGtvX2Rvd25fZ28kcmVhYwpgYGAKCiMjIE5vcm1hbCBkbGduIHRyYW5zbGF0b21lIHZzIGtub2Nrb3V0IGRsZ24gdHJhbnNsYXRvbWUuCgpgYGB7ciBub3JtX2RsZ25fdHJhbnNsYXRvbWVfdnNfa29fZGxnbl90cmFuc2xhdG9tZV9nZnByb2ZpbGVyLCBldmFsPUZBTFNFfQpkbGdubm9ybV93cnRfZGxnbmtvX3RyYW5zbGF0b21lIDwtIHRyYW5zbGF0b21lX3Bsb3R0ZXIocGFpcl9tdHJ4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeF9heGlzPSJub3JtZGxnbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2F4aXM9ImtvZGxnbiIpCmRsZ25ub3JtX3dydF9kbGdua29fdHJhbnNsYXRvbWUkcGxvdApkbGdubm9ybV93cnRfZGxnbmtvX3VwX2dvIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzPWRsZ25ub3JtX3dydF9kbGdua29fdHJhbnNsYXRvbWUkdXBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2llcz0ibW11c2N1bHVzIikKZGxnbm5vcm1fd3J0X2RsZ25rb19kb3duX2dvIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzPWRsZ25ub3JtX3dydF9kbGdua29fdHJhbnNsYXRvbWUkZG93bnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9Im1tdXNjdWx1cyIpCmRsZ25ub3JtX3dydF9kbGdua29fZG93bl9nbyRnbwpgYGAKCiMjIGRsZ24ga25vY2tvdXQgdHJhbnNsYXRvbWUgdnMuIHNjbiBrbm9ja291dCB0cmFuc2xhdG9tZS4KCmBgYHtyIGRsZ25fa29fdHJhbnNsYXRvbWVfdnNfc2NuX2tvX3RyYW5zbGF0b21lX2dwcm9maWxlciwgZXZhbD1GQUxTRX0KZGxnbmtvX3dydF9zY25rb190cmFuc2xhdG9tZSA8LSB0cmFuc2xhdG9tZV9wbG90dGVyKHBhaXJfbXRyeCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhfYXhpcz0ia29kbGduIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfYXhpcz0ia29zY24iKQpkbGdua29fd3J0X3NjbmtvX3RyYW5zbGF0b21lJHBsb3QKZGxnbmtvX3dydF9zY25rb191cF9nbyA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNpZ19nZW5lcz1kbGdua29fd3J0X3NjbmtvX3RyYW5zbGF0b21lJHVwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXM9Im1tdXNjdWx1cyIpCmRsZ25rb193cnRfc2Nua29fdXBfZ28kZ28KZGxnbmtvX3dydF9zY25rb191cF9nbyRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3ZlcgpkbGdua29fd3J0X3NjbmtvX2Rvd25fZ28gPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9ZGxnbmtvX3dydF9zY25rb190cmFuc2xhdG9tZSRkb3ducywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2llcz0ibW11c2N1bHVzIikKZGxnbmtvX3dydF9zY25rb19kb3duX2dvJGdvCmBgYAoKIyBTb21lIHBpY3R1cmVzCgpBcyBJIHVuZGVyc3RhbmQgaXQsIHRoZXJlIGlzIHNvbWUgaW50ZXJlc3QgaW4gYW4gb250b2xvZ3kgc2VhcmNoIHVzaW5nIHRoZSByYXRpbyBvZiByYXRpb3MuCgpgYGB7ciBvdGhlcl9jb250cmFzdHMsIGV2YWw9RkFMU0V9CnJvciA8LSBub3Jta29fcmV0ZGxnbgp1cF9pZHggPC0gcm9yID49IDEKZG93bl9pZHggPC0gcm9yIDw9IC0xCnJvcl91cCA8LSByb3JbdXBfaWR4XQpsZW5ndGgocm9yX3VwKQpyb3JfZG93biA8LSByb3JbZG93bl9pZHhdCmxlbmd0aChyb3JfZG93bikKCnJvcl9ncHJvZmlsZXJfdXAgPC0gc2ltcGxlX2dwcm9maWxlcigKICBzaWdfZ2VuZXM9cm9yX3VwLCBzcGVjaWVzPSJtbXVzY3VsdXMiLAogIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfW1tX3Jvcl9ncGZvaWxlcl91cC12e3Zlcn0ueGxzeCIpKQpyb3JfZ3Byb2ZpbGVyX3VwJHB2YWx1ZV9wbG90cyRtZnBfcGxvdF9vdmVyCnJvcl9ncHJvZmlsZXJfdXAkcHZhbHVlX3Bsb3RzJGJwcF9wbG90X292ZXIKcm9yX2dwcm9maWxlcl91cCRwdmFsdWVfcGxvdHMkY2NwX3Bsb3Rfb3Zlcgpyb3JfZ3Byb2ZpbGVyX3VwJHB2YWx1ZV9wbG90cyR0Zl9wbG90X292ZXIKcm9yX2dwcm9maWxlcl91cCRwdmFsdWVfcGxvdHMkaHBfcGxvdF9vdmVyCgpyb3JfZ3Byb2ZpbGVyX2Rvd24gPC0gc2ltcGxlX2dwcm9maWxlcigKICBzaWdfZ2VuZXM9cm9yX2Rvd24sIHNwZWNpZXM9Im1tdXNjdWx1cyIsCiAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9bW1fcm9yX2dwZm9pbGVyX2Rvd24tdnt2ZXJ9Lnhsc3giKSkKcm9yX2dwcm9maWxlcl9kb3duJHB2YWx1ZV9wbG90cyRtZnBfcGxvdF9vdmVyCnJvcl9ncHJvZmlsZXJfZG93biRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3Zlcgpyb3JfZ3Byb2ZpbGVyX2Rvd24kcHZhbHVlX3Bsb3RzJHJlYWN0b21lX3Bsb3Rfb3Zlcgpyb3JfZ3Byb2ZpbGVyX2Rvd24kcHZhbHVlX3Bsb3RzJGNjcF9wbG90X292ZXIKcm9yX2dwcm9maWxlcl9kb3duJHB2YWx1ZV9wbG90cyR0Zl9wbG90X292ZXIKYGBgCgpgYGB7ciBzYXZlbWUsIGV2YWw9RkFMU0V9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCgoKYGBge3IgbG9hZG1lLCBldmFsPUZBTFNFfQpsb2FkbWUoZmlsZW5hbWU9dGhpc19zYXZlKQpgYGAK