Installing DESeq2

DESeq2 is a bioconductor package that should be installed via two main ways as follows:

Via bioconductor

#BiocManager::install('DESeq2')

Via DESeq2 github repository

library(devtools)
#install_github('mikelove/DESeq2')

DESeq2 tutorials

DESeq2 is one of the important parametric methods that have been used to analyze RNA-seq data.

Main tutorial

Click

Different workshops

Working with DESeq2

Dataset from stool

da <- load("RDA/PregnancyClosed15.Rdata")
site <- "Stool"
phy <- PSPreg[[site]]
phy
phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 1271 taxa and 580 samples ]
sample_data() Sample Data:       [ 580 samples by 64 sample variables ]
tax_table()   Taxonomy Table:    [ 1271 taxa by 7 taxonomic ranks ]
phy_tree()    Phylogenetic Tree: [ 1271 tips and 1270 internal nodes ]

Remove rare taxa

phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 894 taxa and 580 samples ]
sample_data() Sample Data:       [ 580 samples by 64 sample variables ]
tax_table()   Taxonomy Table:    [ 894 taxa by 7 taxonomic ranks ]
phy_tree()    Phylogenetic Tree: [ 894 tips and 893 internal nodes ]

In our phyloseq dataset taxa are columns I shall change that, i.e. taxa are rows. I think it might be other ways, but it works.

OTU1 = as(otu_table(phy), "matrix")
if (taxa_are_rows(phy) == FALSE) {
    OTU1 <- t(OTU1)
}
OTUdf = as.data.frame(OTU1)
otu_table(phy) <- otu_table(OTUdf, taxa_are_rows = T)
identical(rownames(otu_table(phy)), rownames(tax_table(phy)))
[1] TRUE

Genus level

DESeq2 result table

Showing the only taxa with adjusted p_value less than 0.05

baseMean log2FoldChange lfcSE stat pvalue padj
P:TM7 22.378945 21.800010 1.3082080 16.664025 0.0000000 0.0000000
Catenibacterium 13.165041 21.583812 1.8157221 11.887178 0.0000000 0.0000000
Megamonas 24.837902 21.939255 2.2458012 9.769010 0.0000000 0.0000000
Faecalibacterium 204.965993 4.013791 0.4535050 8.850599 0.0000000 0.0000000
Lachnospira 24.894486 3.679256 0.5590881 6.580816 0.0000000 0.0000000
Ruminococcus 41.095117 2.779825 0.4356648 6.380651 0.0000000 0.0000000
F:Ruminococcaceae 149.260135 1.762760 0.3403647 5.179032 0.0000002 0.0000029
F:Clostridiaceae 13.889536 3.012683 0.5868136 5.133970 0.0000003 0.0000032
F:[Barnesiellaceae] 6.767300 4.845314 0.9654693 5.018611 0.0000005 0.0000049
Streptococcus 18.890254 3.124087 0.6235168 5.010429 0.0000005 0.0000049
F:Christensenellaceae 4.052563 4.582075 0.9271767 4.941965 0.0000008 0.0000063
[Ruminococcus] 14.610026 -1.935456 0.4110902 -4.708107 0.0000025 0.0000188
Bacteroides 873.222633 1.749958 0.3908435 4.477388 0.0000076 0.0000523
Collinsella 2.463040 3.754923 0.8519256 4.407571 0.0000105 0.0000672
Veillonella 3.759663 -4.168777 0.9717439 -4.289996 0.0000179 0.0001072
Butyricimonas 1.612963 3.232938 0.8088162 3.997124 0.0000641 0.0003607
Paraprevotella 12.076234 4.410400 1.1813529 3.733347 0.0001890 0.0010003
Turicibacter 1.305274 3.088718 0.8762512 3.524922 0.0004236 0.0021180
O:Clostridiales 72.068969 1.262931 0.3694253 3.418636 0.0006294 0.0029812
Bifidobacterium 3.663781 2.439840 0.7226954 3.376027 0.0007354 0.0033093
Roseburia 58.905956 1.473149 0.4477803 3.289892 0.0010023 0.0042954
Odoribacter 2.835605 1.933047 0.6383184 3.028342 0.0024590 0.0100595
Anaerostipes 1.105549 2.261156 0.7905448 2.860250 0.0042331 0.0165642
O:Bacteroidales 8.143020 6.212350 2.2408686 2.772296 0.0055662 0.0208734
Varibaculum 1.740448 -2.396173 0.9194651 -2.606051 0.0091593 0.0329734

To understand the result table, see the following notes.

  • baseMean, is the average of the normalized count values, dividing by size factors, taken over all samples.

  • Log2FoldChange, is the effect size estimate. It tells us how much the gene’s expression seems to have changed due to certain factors in the control and study groups for example. This value is reported on a logarithmic scale to base 2: for example, a log2 fold change of 1.5 means that the gene’s expression is increased by a multiplicative factor of 2^1.5≈2.82. Of course, this estimate has an uncertainty associated with it, which is available in the column lfcSE.

  • lfcSE, the standard error estimate for the log2 fold change estimate

  • stat, is the Wald statistic: the log2FoldChange divided by lfcSE (the second column divided by the third), which is compared to a standard Normal distribution to generate a two-tailed pvalue. For the likelihood ratio test (LRT), stat is the difference in deviance between the reduced model and the full model, which is compared to a chi-squared distribution to generate a pvalue.

  • pvalue, the raw p-values.

  • padj, adjusted p-value.

  • taxon, the genes names, or the clustered genes as in my table (Operational taxonomic unit, OTU)

Plot

It is showing the differentiated genes.

NULL

More plots

Plotting the relative abundance (CLR) for every gene in the previous table against the ‘Race’ variable factors. These plots are helpful to see the efficiency of DESeq2 in recognizing the differentiated genes

DESeq2 pairwise comparison

DESeq2 pairwise comparison analysis for the categorical variable Race factors. I shall use “American Indian” versus “White”, and we can make the same for the whole combinations of pairwise groups.

baseMean log2FoldChange lfcSE stat pvalue padj
P:TM7 22.378945 -21.800002 1.3082080 -16.664018 0.0000000 0.0000000
Catenibacterium 13.165041 -21.583811 1.8157221 -11.887178 0.0000000 0.0000000
Megamonas 24.837902 -21.941654 2.2458012 -9.770078 0.0000000 0.0000000
Faecalibacterium 204.965993 -4.013791 0.4535050 -8.850599 0.0000000 0.0000000
Lachnospira 24.894486 -3.679256 0.5590881 -6.580816 0.0000000 0.0000000
Ruminococcus 41.095117 -2.779825 0.4356648 -6.380651 0.0000000 0.0000000
F:Ruminococcaceae 149.260135 -1.762760 0.3403647 -5.179032 0.0000002 0.0000029
F:Clostridiaceae 13.889536 -3.012683 0.5868136 -5.133970 0.0000003 0.0000032
F:[Barnesiellaceae] 6.767300 -4.845314 0.9654693 -5.018611 0.0000005 0.0000049
Streptococcus 18.890254 -3.124087 0.6235168 -5.010429 0.0000005 0.0000049
F:Christensenellaceae 4.052563 -4.582075 0.9271767 -4.941965 0.0000008 0.0000063
[Ruminococcus] 14.610026 1.935456 0.4110902 4.708107 0.0000025 0.0000188
Bacteroides 873.222633 -1.749958 0.3908435 -4.477388 0.0000076 0.0000523
Collinsella 2.463040 -3.754923 0.8519256 -4.407571 0.0000105 0.0000672
Veillonella 3.759663 4.168777 0.9717439 4.289996 0.0000179 0.0001072
Butyricimonas 1.612963 -3.232938 0.8088162 -3.997124 0.0000641 0.0003607
Paraprevotella 12.076234 -4.410400 1.1813529 -3.733347 0.0001890 0.0010003
Turicibacter 1.305274 -3.088718 0.8762512 -3.524922 0.0004236 0.0021180
O:Clostridiales 72.068969 -1.262931 0.3694253 -3.418636 0.0006294 0.0029812
Bifidobacterium 3.663781 -2.439840 0.7226954 -3.376027 0.0007354 0.0033093
Roseburia 58.905956 -1.473149 0.4477803 -3.289892 0.0010023 0.0042954
Odoribacter 2.835605 -1.933047 0.6383184 -3.028342 0.0024590 0.0100595
Anaerostipes 1.105549 -2.261156 0.7905448 -2.860250 0.0042331 0.0165642
O:Bacteroidales 8.143020 -6.212350 2.2408686 -2.772296 0.0055662 0.0208734
Varibaculum 1.740448 2.396173 0.9194651 2.606051 0.0091593 0.0329734
LS0tDQp0aXRsZTogJ0RpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgYmFzZWQgb24gdGhlIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiAoREVTZXEyKSAnDQphdXRob3I6ICJXaXNhbSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgICB0b2M6IHRydWUNCiAgICAgIHRvY19kZXB0aDogNA0KICAgICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KIyBJbnN0YWxsaW5nIERFU2VxMg0KREVTZXEyIGlzIGEgYmlvY29uZHVjdG9yIHBhY2thZ2UgdGhhdCBzaG91bGQgYmUgaW5zdGFsbGVkIHZpYSB0d28gbWFpbiB3YXlzIGFzIGZvbGxvd3M6DQoNCiMjIyMgVmlhIGJpb2NvbmR1Y3Rvcg0KDQoNCmBgYHtyIGluc3RhbGxfYmlvYywgZWNobz1UUlVFfQ0KI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCdERVNlcTInKQ0KDQpgYGANCg0KIyMjIyBWaWEgREVTZXEyIGdpdGh1YiByZXBvc2l0b3J5DQoNCg0KYGBge3IgaW5zdGFsbF9naXQsIGVjaG89VFJVRX0NCmxpYnJhcnkoZGV2dG9vbHMpDQojaW5zdGFsbF9naXRodWIoJ21pa2Vsb3ZlL0RFU2VxMicpDQpgYGANCg0KDQoNCmBgYHtyIHBoeWxvc2VxLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHBoeWxvc2VxKQ0KbGlicmFyeShERVNlcTIpDQpsaWJyYXJ5KHZlZ2FuKQ0KI2xpYnJhcnkobWl4T21pY3MpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpY3RvYykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5cikNCm9wdGlvbnMobWF4LnByaW50PSI3NSIpDQogIGtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9OCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9NiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGV2YWw9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNhY2hlPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBwcm9tcHQ9RkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICB0aWR5PVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBjb21tZW50PU5BLA0KICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZT1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmc9RkFMU0UpDQpvcHRzX2tuaXQkc2V0KHdpZHRoPTc1KQ0KYGBgDQoNCiMgREVTZXEyIHR1dG9yaWFscw0KREVTZXEyIGlzIG9uZSBvZiB0aGUgaW1wb3J0YW50IHBhcmFtZXRyaWMgbWV0aG9kcyB0aGF0IGhhdmUgYmVlbiB1c2VkIHRvIGFuYWx5emUgUk5BLXNlcSBkYXRhLg0KDQojIyMgTWFpbiB0dXRvcmlhbA0KW0NsaWNrXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9kZXZlbC9iaW9jL3ZpZ25ldHRlcy9ERVNlcTIvaW5zdC9kb2MvREVTZXEyLmh0bWwpDQoNCiMjIyBEaWZmZXJlbnQgd29ya3Nob3BzDQoNCiogW0ZJcnN0XShodHRwczovL3d3dy5odWJlci5lbWJsLmRlL3VzZXJzL21zbWl0aC9jc2FtYTIwMTkvbWF0ZXJpYWxzL2xlY3R1cmVzL2RpZmZlcmVudGlhbC1leHByZXNzaW9uLzIwMTktMDdfX0NTQU1BX19ERVNlcTIucGRmKQ0KDQoqIFRoaXMgYm9vayBpcyB2ZXJ5IHVzZWZ1bA0KW01vZGVybiBTdGF0aXN0aWNzIGZvciBNb2Rlcm4gQmlvbG9neV0oaHR0cDovL3dlYi5zdGFuZm9yZC5lZHUvY2xhc3MvYmlvczIyMS9ib29rL2luZGV4Lmh0bWwpDQoNCiogKipQaHlsb3NlcSBkYXRhc2V0KioNCkZyb20gdGhlIHNhbWUgcGFwZXIgW1RlbXBvcmFsIGFuZCBzcGF0aWFsIHZhcmlhdGlvbiBvZiB0aGUgaHVtYW4gbWljcm9iaW90YSBkdXJpbmcgcHJlZ25hbmN5XShodHRwczovL3d3dy5wbmFzLm9yZy9jb250ZW50LzExMi8zNS8xMTA2MCkNCg0KIyBXb3JraW5nIHdpdGggREVTZXEyDQoNCiMjIyBEYXRhc2V0IGZyb20gc3Rvb2wNCg0KKiAqKlBoeWxvc2VxIGRhdGFzZXQqKg0KRnJvbSB0aGlzIHBhcGVyIFtUZW1wb3JhbCBhbmQgc3BhdGlhbCB2YXJpYXRpb24gb2YgdGhlIGh1bWFuIG1pY3JvYmlvdGEgZHVyaW5nIHByZWduYW5jeV0oaHR0cHM6Ly93d3cucG5hcy5vcmcvY29udGVudC8xMTIvMzUvMTEwNjApDQoNCmBgYHtyIGRhdGFfdmFnaW5hLCBlY2hvPVQsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KDQpkYTwtIGxvYWQoJ1JEQS9QcmVnbmFuY3lDbG9zZWQxNS5SZGF0YScpDQpzaXRlIDwtICJTdG9vbCINCnBoeSA8LSBQU1ByZWdbW3NpdGVdXQ0KcGh5DQoNCmBgYA0KDQoqKlJlbW92ZSByYXJlIHRheGEqKg0KDQoNCmBgYHtyIHRyYW5zZm9ybS1kYXRhLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGh5X2NvbXAgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocGh5LCBmdW5jdGlvbihPVFUpIE9UVS9zdW0oT1RVKSkNCnBoeV9jb21wPC1wcnVuZV90YXhhKHRheGFfc3VtcyhwaHlfY29tcCkgPiAwLCBwaHlfY29tcCkNCnRheGE8LW5hbWVzKHRheGFfc3VtcyhwaHlfY29tcCkpDQoNCnBoeTwtcHJ1bmVfdGF4YSh0YXhhLCBwaHkpDQojIyMgQ2hlY2sgdXAgZm9yIHJhbmRvbQ0KI1ZpZXcob3R1X3RhYmxlKHBoeV8zMClALkRhdGFbJzE5MDEwMDIyODgnLCc0NDY4MjM0J10pDQojVmlldyhvdHVfdGFibGUocGh5KUAuRGF0YVsnMTkwMTAwMjI4OCcsJzQ0NjgyMzQnXSkNCiNWaWV3KG90dV90YWJsZShwaHlfY29tcClALkRhdGFbJzE5MDEwMDIyODgnLCc0NDY4MjM0J10pDQpwaHkNCmBgYA0KSW4gb3VyIHBoeWxvc2VxIGRhdGFzZXQgKip0YXhhIGFyZSBjb2x1bW5zKiogSSBzaGFsbCBjaGFuZ2UgdGhhdCwgaS5lLiB0YXhhIGFyZSByb3dzLg0KSSB0aGluayBpdCBtaWdodCBiZSBvdGhlciB3YXlzLCBidXQgaXQgd29ya3MuDQoNCmBgYHtyIGRlc2VxMl9wcmVwLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVQsIHdhcm5pbmc9RkFMU0V9DQpPVFUxID0gYXMob3R1X3RhYmxlKHBoeSksICJtYXRyaXgiKQ0KaWYodGF4YV9hcmVfcm93cyhwaHkpPT0gRkFMU0Upe09UVTEgPC0gdChPVFUxKX0NCk9UVWRmID0gYXMuZGF0YS5mcmFtZShPVFUxKQ0Kb3R1X3RhYmxlKHBoeSk8LSBvdHVfdGFibGUoT1RVZGYsIHRheGFfYXJlX3Jvd3MgPSBUKQ0KaWRlbnRpY2FsKHJvd25hbWVzKG90dV90YWJsZShwaHkpKSxyb3duYW1lcyh0YXhfdGFibGUocGh5KSkpDQpgYGANCg0KIyMgR2VudXMgbGV2ZWwNCg0KDQpgYGB7ciB0cmFuc2Zvcm0tZ2VudXMsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwaHlfZ2VudXM8LSBtaWNyb2Jpb21lOjphZ2dyZWdhdGVfdGF4YShwaHksICdHZW51cycpDQoNCmBgYA0KDQoNCg0KDQoNCiMjIyMgREVTZXEyIHJlc3VsdCB0YWJsZQ0KDQpTaG93aW5nIHRoZSBvbmx5IHRheGEgd2l0aCBhZGp1c3RlZCBwX3ZhbHVlIGxlc3MgdGhhbiAwLjA1DQoNCmBgYHtyIGRlc2VxMl9yZXN1bHQsIG1lc3NhZ2U9RkFMU0UsIGVjaG89Riwgd2FybmluZz1GQUxTRX0NCmRzMjwtcGh5bG9zZXFfdG9fZGVzZXEyKHBoeXNlcSA9IHBoeV9nZW51cywgfiBSYWNlKQ0KZGRzRzwtZXN0aW1hdGVTaXplRmFjdG9ycyhkczIsIHR5cGUgPSAncG9zY291bnRzJykgIyNCeSBNaWNoZWFsDQoNCmRzczwtIERFU2VxKGRkc0cpDQpyZXM8LSByZXN1bHRzKGRzcykNCmRmPC1hcy5kYXRhLmZyYW1lKHJlcykNCmRmIDwtIGRmICU+JSBhcnJhbmdlKHBhZGosIGRlc2MoYWJzKGxvZzJGb2xkQ2hhbmdlKSkpICU+JSBmaWx0ZXIocGFkaiA8IDAuMDUpDQoNCmxpYnJhcnkoa25pdHIpDQprYWJsZShkZikNCmBgYA0KDQoNCioqVG8gdW5kZXJzdGFuZCB0aGUgcmVzdWx0IHRhYmxlLCBzZWUgdGhlIGZvbGxvd2luZyBub3Rlcy4qKg0KDQoqCWJhc2VNZWFuLCBpcyB0aGUgYXZlcmFnZSBvZiB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZXMsIGRpdmlkaW5nIGJ5IHNpemUgZmFjdG9ycywgdGFrZW4gb3ZlciBhbGwgc2FtcGxlcy4NCg0KKglMb2cyRm9sZENoYW5nZSwgaXMgdGhlIGVmZmVjdCBzaXplIGVzdGltYXRlLiBJdCB0ZWxscyB1cyBob3cgbXVjaCB0aGUgZ2VuZSdzIGV4cHJlc3Npb24gc2VlbXMgdG8gaGF2ZSBjaGFuZ2VkIGR1ZSB0byBjZXJ0YWluIGZhY3RvcnMgaW4gdGhlIGNvbnRyb2wgYW5kIHN0dWR5IGdyb3VwcyBmb3IgZXhhbXBsZS4gVGhpcyB2YWx1ZSBpcyByZXBvcnRlZCBvbiBhIGxvZ2FyaXRobWljIHNjYWxlIHRvIGJhc2UgMjogZm9yIGV4YW1wbGUsIGEgbG9nMiBmb2xkIGNoYW5nZSBvZiAxLjUgbWVhbnMgdGhhdCB0aGUgZ2VuZSdzIGV4cHJlc3Npb24gaXMgaW5jcmVhc2VkIGJ5IGEgbXVsdGlwbGljYXRpdmUgZmFjdG9yIG9mIDJeMS414omIMi44Mi4gIE9mIGNvdXJzZSwgdGhpcyBlc3RpbWF0ZSBoYXMgYW4gdW5jZXJ0YWludHkgYXNzb2NpYXRlZCB3aXRoIGl0LCB3aGljaCBpcyBhdmFpbGFibGUgaW4gdGhlIGNvbHVtbiBsZmNTRS4NCg0KKiBsZmNTRSwgdGhlIHN0YW5kYXJkIGVycm9yIGVzdGltYXRlIGZvciB0aGUgbG9nMiBmb2xkIGNoYW5nZSBlc3RpbWF0ZQ0KDQoqCXN0YXQsIGlzIHRoZSBXYWxkIHN0YXRpc3RpYzogdGhlIGxvZzJGb2xkQ2hhbmdlIGRpdmlkZWQgYnkgbGZjU0UgKHRoZSBzZWNvbmQgY29sdW1uIGRpdmlkZWQgYnkgdGhlIHRoaXJkKSwgd2hpY2ggaXMgY29tcGFyZWQgdG8gYSBzdGFuZGFyZCBOb3JtYWwgZGlzdHJpYnV0aW9uIHRvIGdlbmVyYXRlIGEgdHdvLXRhaWxlZCBwdmFsdWUuIEZvciB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0IChMUlQpLCBzdGF0IGlzIHRoZSBkaWZmZXJlbmNlIGluIGRldmlhbmNlIGJldHdlZW4gdGhlIHJlZHVjZWQgbW9kZWwgYW5kIHRoZSBmdWxsIG1vZGVsLCB3aGljaCBpcyBjb21wYXJlZCB0byBhIGNoaS1zcXVhcmVkIGRpc3RyaWJ1dGlvbiB0byBnZW5lcmF0ZSBhIHB2YWx1ZS4NCg0KKglwdmFsdWUsIHRoZSByYXcgcC12YWx1ZXMuDQoNCioJcGFkaiwgYWRqdXN0ZWQgcC12YWx1ZS4NCg0KKiB0YXhvbiwgdGhlIGdlbmVzIG5hbWVzLCBvciB0aGUgY2x1c3RlcmVkIGdlbmVzIGFzIGluIG15IHRhYmxlIChPcGVyYXRpb25hbCB0YXhvbm9taWMgdW5pdCwgT1RVKQ0KDQojIyMjIFBsb3QNCkl0IGlzIHNob3dpbmcgdGhlIGRpZmZlcmVudGlhdGVkIGdlbmVzLiANCg0KDQpgYGB7ciBkZXNlcTJfcGxvdCwgbWVzc2FnZT1GQUxTRSwgZWNobz1GLCB3YXJuaW5nPUZBTFNFLCBldmFsPVRSVUV9DQpwPC1ERVNlcTI6OnBsb3RNQShyZXMpDQpwcmludChwKQ0KYGBgDQoNCiMgTW9yZSBwbG90cw0KDQpQbG90dGluZyB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlIChDTFIpIGZvciBldmVyeSBnZW5lIGluIHRoZSBwcmV2aW91cyB0YWJsZSBhZ2FpbnN0IHRoZSAnUmFjZScgdmFyaWFibGUgZmFjdG9ycy4gVGhlc2UgcGxvdHMgYXJlIGhlbHBmdWwgdG8gc2VlIHRoZSBlZmZpY2llbmN5IG9mIERFU2VxMiBpbiByZWNvZ25pemluZyB0aGUgZGlmZmVyZW50aWF0ZWQgZ2VuZXMNCg0KYGBge3IgdG9wc19nZW51cywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGggPSAiMzMlIiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Nn0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGdnYmVlc3dhcm0pDQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gMTUpKQ0KdG9wLnRheGE8LXJvd25hbWVzKGRmKQ0KZGYxIDwtIGdldF92YXJpYWJsZShwaHlfZ2VudXMpDQpwcyA8LSBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocGh5X2dlbnVzLCAnY2xyJykNCmZvciAodGF4IGluIHRvcC50YXhhKSB7DQogIGRmMSR0YXhhIDwtIGdldF90YXhhKHBzKVt0YXgsIF0NCiAgcCA8LSBnZ3Bsb3QoZGYxLCBhZXMoeCA9IFJhY2UsIHkgPSB0YXhhLCBmaWxsPSBSYWNlKSkgKyBnZW9tX2JveHBsb3QoKSsgZ2VvbV9qaXR0ZXIod2lkdGggPSAuMikrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMSkpKyBsYWJzKHggPSAiR2VudXMiLCB5ID0gIlJlbGF0aXZlIGFidW5kYW5jZSAoQ0xSKSIsIHRpdGxlID0gdGF4KQ0KICBwcmludChwKQ0KfQ0KDQoNCmBgYA0KDQoNCg0KIyBERVNlcTIgcGFpcndpc2UgY29tcGFyaXNvbiANCg0KREVTZXEyIHBhaXJ3aXNlIGNvbXBhcmlzb24gYW5hbHlzaXMgZm9yIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBSYWNlIGZhY3RvcnMuDQpJIHNoYWxsIHVzZSAiQW1lcmljYW4gSW5kaWFuIiB2ZXJzdXMgIldoaXRlIiwgYW5kIHdlIGNhbiBtYWtlIHRoZSBzYW1lIGZvciB0aGUgd2hvbGUgY29tYmluYXRpb25zIG9mIHBhaXJ3aXNlIGdyb3Vwcy4NCg0KYGBge3IgdG9wc19nZW51c19wYWlyd2lzZSwgZWNobz1GLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aCA9ICIzMyUiLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02fQ0KZGYxJFJhY2U8LSBmYWN0b3IoZGYxJFJhY2UsIGxldmVscyA9IGMoJ0FtZXJpY2FuIEluZGlhbicsICdXaGl0ZScsJ0FzaWFuLUphcGFuZXNlJywnQXNpYW4tVW5zcGVjaWZpZWQnLCdQYWNpZmljIElzbGFuZGVyJywnQmxhY2snLCdPdGhlciAoU3BlY2lmeSBiZWxvdyknLCdBc2lhbi1DaGluZXNlJywnSW5kaWFuJykpDQpzYW1wbGVfZGF0YShwaHlfZ2VudXMpPC0gZGYxDQojIw0KZHMyXzE8LXBoeWxvc2VxX3RvX2Rlc2VxMihwaHlzZXEgPSBwaHlfZ2VudXMsIH4gUmFjZSkNCmRkc0c8LWVzdGltYXRlU2l6ZUZhY3RvcnMoZHMyXzEsIHR5cGUgPSAncG9zY291bnRzJykgIyNCeSBNaWNoZWFsDQoNCmRzczwtIERFU2VxKGRkc0cpDQplX0FtX1doPC0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKGRzcywgY29udHJhc3Q9YygiUmFjZSIsIkFtZXJpY2FuIEluZGlhbiIsIldoaXRlIikpKQ0KZV9BbV9XaCA8LSBlX0FtX1doICU+JSBhcnJhbmdlKHBhZGosIGRlc2MoYWJzKGxvZzJGb2xkQ2hhbmdlKSkpICU+JSBmaWx0ZXIocGFkaiA8IDAuMDUpDQoNCmxpYnJhcnkoa25pdHIpDQprYWJsZShlX0FtX1doKQ0KYGBgDQoNCg0K