Reference and Resources

Nature Protocols volume 8, pages 1494-1512 (2013)

AWS instance: m4.xlarge

Required libraries

library(ballgown); library(genefilter); library(dplyr); library(devtools); library(gplots); library(ggfortify)

Attaching package: 㤼㸱dplyr㤼㸲

The following objects are masked from 㤼㸱package:ballgown㤼㸲:

    contains, expr, last

The following objects are masked from 㤼㸱package:stats㤼㸲:

    filter, lag

The following objects are masked from 㤼㸱package:base㤼㸲:

    intersect, setdiff, setequal, union


Attaching package: 㤼㸱gplots㤼㸲

The following object is masked from 㤼㸱package:stats㤼㸲:

    lowess

Loading required package: ggplot2

Attaching package: 㤼㸱ggplot2㤼㸲

The following object is masked from 㤼㸱package:ballgown㤼㸲:

    expr

Typical contents of a ballgown directory/sub-directory

ls -l ballgown/Sp_ds/

-rw-rw-r– 1 ubuntu ubuntu 1460476 Mar 5 05:15 Sp_ds.gtf

-rw-rw-r– 1 ubuntu ubuntu 49218 Mar 5 05:15 e2t.ctab

-rw-rw-r– 1 ubuntu ubuntu 364883 Mar 5 05:15 e_data.ctab

-rw-rw-r– 1 ubuntu ubuntu 664 Mar 5 05:15 i2t.ctab

-rw-rw-r– 1 ubuntu ubuntu 2516 Mar 5 05:15 i_data.ctab

-rw-rw-r– 1 ubuntu ubuntu 407989 Mar 5 05:15 t_data.ctab

Convert the StringTie data to Ballgown data

data_directory="C:/Users/bhagi/Documents/NGS_data_analysis/tuxedo2_S_pombe/ballgown"
data_directory
[1] "C:/Users/bhagi/Documents/NGS_data_analysis/tuxedo2_S_pombe/ballgown"
bg=ballgown(dataDir=data_directory, samplePattern="S", meas="all")
Sun Mar 24 13:34:53 2019
Sun Mar 24 13:34:53 2019: Reading linking tables
Sun Mar 24 13:34:53 2019: Reading intron data files
Sun Mar 24 13:34:53 2019: Merging intron data
Sun Mar 24 13:34:53 2019: Reading exon data files
Sun Mar 24 13:34:54 2019: Merging exon data
Sun Mar 24 13:34:54 2019: Reading transcript data files
Sun Mar 24 13:34:54 2019: Merging transcript data
Wrapping up the results
Sun Mar 24 13:34:54 2019

Structure of the ballgown data and its components

structure(bg)
$intron
GRanges object with 62 ranges and 2 metadata columns:
              seqnames    ranges strand |        id transcripts
                 <Rle> <IRanges>  <Rle> | <integer> <character>
   [1]   SPAC144.02_T0   143-190      + |         1         258
   [2]  SPAC1486.05_T0 2883-2947      + |         2         282
   [3] SPAC1639.01c_T0  962-1078      + |         3         360
   [4] SPAC17H9.14c_T0   556-623      + |         4         557
   [5] SPAC1851.04c_T0 2590-2650      - |         5         595
   ...             ...       ...    ... .       ...         ...
  [58]   SPBC577.11_T0   213-258      + |        58        3789
  [59] SPBP35G2.04c_T0   165-248      + |        59        4078
  [60]  SPCC1235.01_T0   946-985      + |        60        4221
  [61]   SPCC417.04_T0   151-212      - |        61        4707
  [62]  SPCC663.01c_T0 2156-2230      + |        62        4890
  -------
  seqinfo: 36 sequences from an unspecified genome; no seqlengths

$exon
GRanges object with 5114 ranges and 2 metadata columns:
                seqnames    ranges strand |        id transcripts
                   <Rle> <IRanges>  <Rle> | <integer> <character>
     [1]  SPAC1002.01_T0     3-480      + |         1           1
     [2]  SPAC1002.02_T0     1-690      + |         2           2
     [3] SPAC1002.03c_T0    1-2772      + |         3           3
     [4] SPAC1002.04c_T0     1-600      + |         4           4
     [5] SPAC1002.05c_T0   11-2134      + |         5           5
     ...             ...       ...    ... .       ...         ...
  [5110] SPCPB1C11.02_T0    1-1518      + |      5110        5055
  [5111] SPCPB1C11.03_T0    1-1695      + |      5111        5056
  [5112]  SPCPJ732.01_T0     1-558      - |      5112        5057
  [5113]  SPCPJ732.01_T0    1-1731      + |      5113        5058
  [5114] SPCPJ732.02c_T0    3-1666      + |      5114        5059
  -------
  seqinfo: 4640 sequences from an unspecified genome; no seqlengths

$trans
GRangesList object of length 5059:
$1 
GRanges object with 1 range and 2 metadata columns:
            seqnames    ranges strand |        id transcripts
               <Rle> <IRanges>  <Rle> | <integer> <character>
  [1] SPAC1002.01_T0     3-480      + |         1           1

$2 
GRanges object with 1 range and 2 metadata columns:
            seqnames ranges strand | id transcripts
  [1] SPAC1002.02_T0  1-690      + |  2           2

$3 
GRanges object with 1 range and 2 metadata columns:
             seqnames ranges strand | id transcripts
  [1] SPAC1002.03c_T0 1-2772      + |  3           3

...
<5056 more elements>
-------
seqinfo: 4640 sequences from an unspecified genome; no seqlengths

Create metadata/phenotype data (pData) for the ballgown data to perform differential analysis (DE)

For demonstration purposes: We will combine Sp_ds and Sp_hs as replicates. Similarly, combine Sp_plat and Sp_log as replicates.

pData(bg)=data.frame(id=sampleNames(bg), group=factor(c(1,1,2,2)))

Names of the components

names(structure(bg))
[1] "intron" "exon"   "trans" 

Structure of exons

structure(bg)$exon
GRanges object with 5114 ranges and 2 metadata columns:
                seqnames    ranges strand |        id transcripts
                   <Rle> <IRanges>  <Rle> | <integer> <character>
     [1]  SPAC1002.01_T0     3-480      + |         1           1
     [2]  SPAC1002.02_T0     1-690      + |         2           2
     [3] SPAC1002.03c_T0    1-2772      + |         3           3
     [4] SPAC1002.04c_T0     1-600      + |         4           4
     [5] SPAC1002.05c_T0   11-2134      + |         5           5
     ...             ...       ...    ... .       ...         ...
  [5110] SPCPB1C11.02_T0    1-1518      + |      5110        5055
  [5111] SPCPB1C11.03_T0    1-1695      + |      5111        5056
  [5112]  SPCPJ732.01_T0     1-558      - |      5112        5057
  [5113]  SPCPJ732.01_T0    1-1731      + |      5113        5058
  [5114] SPCPJ732.02c_T0    3-1666      + |      5114        5059
  -------
  seqinfo: 4640 sequences from an unspecified genome; no seqlengths

Structure of introns

structure(bg)$intron
GRanges object with 62 ranges and 2 metadata columns:
              seqnames    ranges strand |        id transcripts
                 <Rle> <IRanges>  <Rle> | <integer> <character>
   [1]   SPAC144.02_T0   143-190      + |         1         258
   [2]  SPAC1486.05_T0 2883-2947      + |         2         282
   [3] SPAC1639.01c_T0  962-1078      + |         3         360
   [4] SPAC17H9.14c_T0   556-623      + |         4         557
   [5] SPAC1851.04c_T0 2590-2650      - |         5         595
   ...             ...       ...    ... .       ...         ...
  [58]   SPBC577.11_T0   213-258      + |        58        3789
  [59] SPBP35G2.04c_T0   165-248      + |        59        4078
  [60]  SPCC1235.01_T0   946-985      + |        60        4221
  [61]   SPCC417.04_T0   151-212      - |        61        4707
  [62]  SPCC663.01c_T0 2156-2230      + |        62        4890
  -------
  seqinfo: 36 sequences from an unspecified genome; no seqlengths

Structure of transcripts

structure(bg)$trans
GRangesList object of length 5059:
$1 
GRanges object with 1 range and 2 metadata columns:
            seqnames    ranges strand |        id transcripts
               <Rle> <IRanges>  <Rle> | <integer> <character>
  [1] SPAC1002.01_T0     3-480      + |         1           1

$2 
GRanges object with 1 range and 2 metadata columns:
            seqnames ranges strand | id transcripts
  [1] SPAC1002.02_T0  1-690      + |  2           2

$3 
GRanges object with 1 range and 2 metadata columns:
             seqnames ranges strand | id transcripts
  [1] SPAC1002.03c_T0 1-2772      + |  3           3

...
<5056 more elements>
-------
seqinfo: 4640 sequences from an unspecified genome; no seqlengths

FPKM values for each transcript

transcript_fpkm = texpr(bg, "FPKM")
head(transcript_fpkm)
  FPKM.Sp_ds FPKM.Sp_hs FPKM.Sp_log FPKM.Sp_plat
1   26.83887   10.66771    27.71478     31.47178
2  167.16380   59.38688    78.52016    110.63217
3  141.24464   74.06425    90.76392    118.90112
4   43.37009   40.40438    28.87185     47.15420
5   29.76646   18.64130    13.50993     56.32640
6  167.24104  388.51425   180.40793     66.16932

Coverage information for each transcript

transcript_cov = texpr(bg, "cov")
head(transcript_cov)
  cov.Sp_ds cov.Sp_hs cov.Sp_log cov.Sp_plat
1  2.506276  0.987448   2.822176    2.700837
2 15.610145  5.497101   7.995652    9.494203
3 13.189754  6.855700   9.242424   10.203824
4  4.050000  3.740000   2.940000    4.046667
5  2.779661  1.725518   1.375706    4.833804
6 15.617357 35.962524  18.370810    5.678501

Descriptive stats for each transcripts

whole_tx_table = texpr(bg, "all")
head(whole_tx_table)

Isolate multi-map-corrected average per-base read coverage for each exon

exon_mcov = eexpr(bg, "mcov")
head(exon_mcov)
  mcov.Sp_ds mcov.Sp_hs mcov.Sp_log mcov.Sp_plat
1     2.5000     0.9874      2.8201       2.7008
2    15.6029     5.6942      7.9899       9.4928
3    13.1898     6.8557      9.2424      10.2035
4     4.0483     3.7400      2.9400       4.0450
5     2.7792     1.7255      1.3757       4.8338
6    15.6154    35.9428     18.3708       5.6765

Isolate read count for each intron

junction_recount = iexpr(bg)
head(junction_recount)
  rcount.Sp_ds rcount.Sp_hs rcount.Sp_log rcount.Sp_plat
1            7            4             7              5
2            1            0             0              0
3            1            1             8              5
4            6            0             0              0
5            0            0             0              5
6           74           20            17             46

Isolate stats for intron

whole_intron_table = iexpr(bg, "all")
head(whole_intron_table)

Isolate gene level expression

gene_expression = gexpr(bg)
head(gene_expression)
           FPKM.Sp_ds FPKM.Sp_hs FPKM.Sp_log FPKM.Sp_plat
MSTRG.1      26.83887  10.667706    27.71478    31.471781
MSTRG.10    299.36441 286.959656  1263.90503   227.950562
MSTRG.100    38.39506   5.345963    21.96203    45.426273
MSTRG.1000   17.89546  65.530449    51.28185     5.700558
MSTRG.1001  199.42723 132.961121    95.39095   223.718674
MSTRG.1002   82.37018  79.360672   125.50716    67.473282

Boxplots for transcript expression (by FPKM) for each sample

transcript_fpkm_log2 = log2(transcript_fpkm + 1)
par(mar = c(10, 4, 4, 2))
boxplot(transcript_fpkm_log2, col = as.numeric(pData(bg)$group), las=2, ylab="log2(FPKM + 1)")

Plot heatmap of transcript FPKM across all samples

cols = colorpanel(99, "blue", "black", "yellow")
heatmap.2(transcript_fpkm_log2, density.info = "none", trace = "none", margins = c(8, 5), cexCol = 1.2, keysize = 1,
          col = cols, scale = "none")
Error in plot.new() : figure margins too large

Principal component analysis (PCA)

pca = (prcomp(t(transcript_fpkm_log2)))
autoplot(pca, data=pData(bg), colour = "group", label = T, label.label = "id" )

Extract indexes from ballgown object

names(indexes(bg))
[1] "e2t"      "i2t"      "t2g"      "bamfiles" "pData"   

Map exons to transcripts

head(indexes(bg)$e2t)

Map introns to transcripts

head(indexes(bg)$i2t)

Map transcripts to genes

head(indexes(bg)$t2g)

Mapping exons to transcripts and transcripts to gene

rr exon_transcript_table = indexes(bg)\(e2t transcript_gene_table = indexes(bg)\)t2g head(transcript_gene_table)

Test for differential expression by transcripts and genes

results_transcripts = stattest(bg, feature = "transcript", meas = "FPKM", covariate = "group", getFC = TRUE)
head(results_transcripts)
write.table(results_transcripts, file = "ballgown_transcript_results.txt", sep = "\t", quote = F, row.names = F)

rr results_genes = stattest(bg, feature = , meas = , covariate = , getFC = TRUE) head(results_genes) r write.table(results_genes, file = _gene_results.txt, sep = \t, quote = F, row.names = F)

Identify and sort (increasing) the genes and the transcripts by their p-values

results_genes <- arrange(results_genes, pval)
head(results_genes)
results_transcripts <- data.frame(geneIDs=ballgown::geneIDs(bg), results_transcripts)
results_transcripts <- arrange(results_transcripts, pval)
head(results_transcripts)

Plot the transcripts for a gene across samples

plotTranscripts(gene = "MSTRG.2282", gown = bg, samples = sampleNames(bg), meas = "FPKM", colorby = "transcript",
                main = "transcripts from gene MSTRG.2282")

Boxplot for most diffrentially expressed transcript

idx <- which(geneIDs(bg)=="MSTRG.2282")
idx
2313 
2313 
plot(transcript_fpkm_log2[idx, ] ~ pData(bg)$group, border=c(1, 2), main=paste(ballgown::geneIDs(bg)[idx]),
     pch=19, xlab="Group", ylab="log2(FPKM+1)")
points(transcript_fpkm_log2[idx,] ~ jitter(as.numeric(pData(bg)$group)), col=as.numeric(pData(bg)$group), pch=20)

LS0tDQp0aXRsZTogIlR1eGVkbyB0b29scyAyIChQYXJ0IElJSSkgLSBEaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzIHVzaW5nIEJhbGxnb3duIg0KYXV0aG9yOiBCaGFnaXJhdGhpIERhc2gNCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KIyBSZWZlcmVuY2UgYW5kIFJlc291cmNlcw0KDQojIyMgTmF0dXJlIFByb3RvY29scyB2b2x1bWUgOCwgcGFnZXMgMTQ5NC0xNTEyICgyMDEzKQ0KDQojIyMgRGF0YSBAIFtsaW5rXSBodHRwOi8vc291cmNlZm9yZ2UubmV0L3Byb2plY3RzL3RyaW5pdHlybmFzZXEvZmlsZXMvbWlzYy9UcmluaXR5TmF0dXJlUHJvdG9jb2xUdXRvcmlhbC50Z3oNCg0KIyMjIEFXUyBpbnN0YW5jZTogbTQueGxhcmdlDQoNCg0KIyBSZXF1aXJlZCBsaWJyYXJpZXMNCg0KYGBge3J9DQpsaWJyYXJ5KGJhbGxnb3duKTsgbGlicmFyeShnZW5lZmlsdGVyKTsgbGlicmFyeShkcGx5cik7IGxpYnJhcnkoZGV2dG9vbHMpOyBsaWJyYXJ5KGdwbG90cyk7IGxpYnJhcnkoZ2dmb3J0aWZ5KQ0KYGBgDQoNCg0KIyMgVHlwaWNhbCBjb250ZW50cyBvZiBhIGJhbGxnb3duIGRpcmVjdG9yeS9zdWItZGlyZWN0b3J5DQoNCiMjIyMgbHMgLWwgYmFsbGdvd24vU3BfZHMvDQoNCi1ydy1ydy1yLS0gMSB1YnVudHUgdWJ1bnR1IDE0NjA0NzYgTWFyICA1IDA1OjE1IFNwX2RzLmd0Zg0KDQotcnctcnctci0tIDEgdWJ1bnR1IHVidW50dSAgIDQ5MjE4IE1hciAgNSAwNToxNSBlMnQuY3RhYg0KDQotcnctcnctci0tIDEgdWJ1bnR1IHVidW50dSAgMzY0ODgzIE1hciAgNSAwNToxNSBlX2RhdGEuY3RhYg0KDQotcnctcnctci0tIDEgdWJ1bnR1IHVidW50dSAgICAgNjY0IE1hciAgNSAwNToxNSBpMnQuY3RhYg0KDQotcnctcnctci0tIDEgdWJ1bnR1IHVidW50dSAgICAyNTE2IE1hciAgNSAwNToxNSBpX2RhdGEuY3RhYg0KDQotcnctcnctci0tIDEgdWJ1bnR1IHVidW50dSAgNDA3OTg5IE1hciAgNSAwNToxNSB0X2RhdGEuY3RhYg0KDQoNCg0KIyMgQ29udmVydCB0aGUgU3RyaW5nVGllIGRhdGEgdG8gQmFsbGdvd24gZGF0YQ0KDQpgYGB7cn0NCmRhdGFfZGlyZWN0b3J5PSJDOi9Vc2Vycy9iaGFnaS9Eb2N1bWVudHMvTkdTX2RhdGFfYW5hbHlzaXMvdHV4ZWRvMl9TX3BvbWJlL2JhbGxnb3duIg0KZGF0YV9kaXJlY3RvcnkNCmBgYA0KDQoNCg0KYGBge3J9DQpiZz1iYWxsZ293bihkYXRhRGlyPWRhdGFfZGlyZWN0b3J5LCBzYW1wbGVQYXR0ZXJuPSJTIiwgbWVhcz0iYWxsIikNCmBgYA0KDQojIyBTdHJ1Y3R1cmUgb2YgdGhlIGJhbGxnb3duIGRhdGEgYW5kIGl0cyBjb21wb25lbnRzDQoNCmBgYHtyfQ0Kc3RydWN0dXJlKGJnKQ0KYGBgDQoNCiMjIENyZWF0ZSBtZXRhZGF0YS9waGVub3R5cGUgZGF0YSAocERhdGEpIGZvciB0aGUgYmFsbGdvd24gZGF0YSB0byBwZXJmb3JtIGRpZmZlcmVudGlhbCBhbmFseXNpcyAoREUpDQoNCiMjIyMgRm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXM6IFdlIHdpbGwgY29tYmluZSBTcF9kcyBhbmQgU3BfaHMgYXMgcmVwbGljYXRlcy4gU2ltaWxhcmx5LCBjb21iaW5lIFNwX3BsYXQgYW5kIFNwX2xvZyBhcyByZXBsaWNhdGVzLiANCg0KYGBge3J9DQpwRGF0YShiZyk9ZGF0YS5mcmFtZShpZD1zYW1wbGVOYW1lcyhiZyksIGdyb3VwPWZhY3RvcihjKDEsMSwyLDIpKSkNCmBgYA0KDQoNCiMjIyMgTmFtZXMgb2YgdGhlIGNvbXBvbmVudHMNCg0KYGBge3J9DQpuYW1lcyhzdHJ1Y3R1cmUoYmcpKQ0KYGBgDQoNCiMjIyMgU3RydWN0dXJlIG9mIGV4b25zDQoNCmBgYHtyfQ0Kc3RydWN0dXJlKGJnKSRleG9uDQpgYGANCg0KIyMjIyBTdHJ1Y3R1cmUgb2YgaW50cm9ucw0KDQpgYGB7cn0NCnN0cnVjdHVyZShiZykkaW50cm9uDQpgYGANCg0KIyMjIyBTdHJ1Y3R1cmUgb2YgdHJhbnNjcmlwdHMNCg0KYGBge3J9DQpzdHJ1Y3R1cmUoYmcpJHRyYW5zDQpgYGANCg0KDQojIyBGUEtNIHZhbHVlcyBmb3IgZWFjaCB0cmFuc2NyaXB0DQoNCmBgYHtyfQ0KdHJhbnNjcmlwdF9mcGttID0gdGV4cHIoYmcsICJGUEtNIikNCmhlYWQodHJhbnNjcmlwdF9mcGttKQ0KYGBgDQoNCg0KIyMgQ292ZXJhZ2UgaW5mb3JtYXRpb24gZm9yIGVhY2ggdHJhbnNjcmlwdA0KDQpgYGB7cn0NCnRyYW5zY3JpcHRfY292ID0gdGV4cHIoYmcsICJjb3YiKQ0KaGVhZCh0cmFuc2NyaXB0X2NvdikNCmBgYA0KDQoNCiMjIERlc2NyaXB0aXZlIHN0YXRzIGZvciBlYWNoIHRyYW5zY3JpcHRzDQoNCmBgYHtyfQ0Kd2hvbGVfdHhfdGFibGUgPSB0ZXhwcihiZywgImFsbCIpDQpoZWFkKHdob2xlX3R4X3RhYmxlKQ0KYGBgDQoNCg0KIyMgSXNvbGF0ZSBtdWx0aS1tYXAtY29ycmVjdGVkIGF2ZXJhZ2UgcGVyLWJhc2UgcmVhZCBjb3ZlcmFnZSBmb3IgZWFjaCBleG9uDQoNCmBgYHtyfQ0KZXhvbl9tY292ID0gZWV4cHIoYmcsICJtY292IikNCmhlYWQoZXhvbl9tY292KQ0KYGBgDQoNCg0KIyMgSXNvbGF0ZSByZWFkIGNvdW50IGZvciBlYWNoIGludHJvbg0KDQpgYGB7cn0NCmp1bmN0aW9uX3JlY291bnQgPSBpZXhwcihiZykNCmhlYWQoanVuY3Rpb25fcmVjb3VudCkNCmBgYA0KDQoNCiMjIElzb2xhdGUgc3RhdHMgZm9yIGludHJvbg0KDQpgYGB7cn0NCndob2xlX2ludHJvbl90YWJsZSA9IGlleHByKGJnLCAiYWxsIikNCmhlYWQod2hvbGVfaW50cm9uX3RhYmxlKQ0KYGBgDQoNCiMjIElzb2xhdGUgZ2VuZSBsZXZlbCBleHByZXNzaW9uDQoNCmBgYHtyfQ0KZ2VuZV9leHByZXNzaW9uID0gZ2V4cHIoYmcpDQpoZWFkKGdlbmVfZXhwcmVzc2lvbikNCmBgYA0KDQoNCiMjIEJveHBsb3RzIGZvciB0cmFuc2NyaXB0IGV4cHJlc3Npb24gKGJ5IEZQS00pIGZvciBlYWNoIHNhbXBsZQ0KDQpgYGB7cn0NCnRyYW5zY3JpcHRfZnBrbV9sb2cyID0gbG9nMih0cmFuc2NyaXB0X2Zwa20gKyAxKQ0KcGFyKG1hciA9IGMoMTAsIDQsIDQsIDIpKQ0KYm94cGxvdCh0cmFuc2NyaXB0X2Zwa21fbG9nMiwgY29sID0gYXMubnVtZXJpYyhwRGF0YShiZykkZ3JvdXApLCBsYXM9MiwgeWxhYj0ibG9nMihGUEtNICsgMSkiKQ0KYGBgDQoNCg0KIyMgUGxvdCBoZWF0bWFwICBvZiB0cmFuc2NyaXB0IEZQS00gYWNyb3NzIGFsbCBzYW1wbGVzDQoNCmBgYHtyfQ0KY29scyA9IGNvbG9ycGFuZWwoOTksICJibHVlIiwgImJsYWNrIiwgInllbGxvdyIpDQpoZWF0bWFwLjIodHJhbnNjcmlwdF9mcGttX2xvZzIsIGRlbnNpdHkuaW5mbyA9ICJub25lIiwgdHJhY2UgPSAibm9uZSIsIG1hcmdpbnMgPSBjKDgsIDUpLCBjZXhDb2wgPSAxLjIsIGtleXNpemUgPSAxLA0KICAgICAgICAgIGNvbCA9IGNvbHMsIHNjYWxlID0gIm5vbmUiKQ0KYGBgDQoNCiMjIFByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSkNCg0KYGBge3J9DQpwY2EgPSAocHJjb21wKHQodHJhbnNjcmlwdF9mcGttX2xvZzIpKSkNCmF1dG9wbG90KHBjYSwgZGF0YT1wRGF0YShiZyksIGNvbG91ciA9ICJncm91cCIsIGxhYmVsID0gVCwgbGFiZWwubGFiZWwgPSAiaWQiICkNCmBgYA0KDQoNCiMjIEV4dHJhY3QgaW5kZXhlcyBmcm9tIGJhbGxnb3duIG9iamVjdA0KDQpgYGB7cn0NCm5hbWVzKGluZGV4ZXMoYmcpKQ0KYGBgDQoNCiMjIE1hcCBleG9ucyB0byB0cmFuc2NyaXB0cw0KDQpgYGB7cn0NCmhlYWQoaW5kZXhlcyhiZykkZTJ0KQ0KYGBgDQoNCg0KDQojIyBNYXAgaW50cm9ucyB0byB0cmFuc2NyaXB0cw0KDQpgYGB7cn0NCmhlYWQoaW5kZXhlcyhiZykkaTJ0KQ0KYGBgDQoNCiMjIE1hcCB0cmFuc2NyaXB0cyB0byBnZW5lcw0KDQpgYGB7cn0NCmhlYWQoaW5kZXhlcyhiZykkdDJnKQ0KYGBgDQoNCiMjIE1hcHBpbmcgZXhvbnMgdG8gdHJhbnNjcmlwdHMgYW5kIHRyYW5zY3JpcHRzIHRvIGdlbmUNCg0KYGBge3J9DQpleG9uX3RyYW5zY3JpcHRfdGFibGUgPSBpbmRleGVzKGJnKSRlMnQNCnRyYW5zY3JpcHRfZ2VuZV90YWJsZSA9IGluZGV4ZXMoYmcpJHQyZw0KaGVhZCh0cmFuc2NyaXB0X2dlbmVfdGFibGUpDQpgYGANCg0KIyMgVGVzdCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYnkgdHJhbnNjcmlwdHMgYW5kIGdlbmVzDQoNCmBgYHtyfQ0KcmVzdWx0c190cmFuc2NyaXB0cyA9IHN0YXR0ZXN0KGJnLCBmZWF0dXJlID0gInRyYW5zY3JpcHQiLCBtZWFzID0gIkZQS00iLCBjb3ZhcmlhdGUgPSAiZ3JvdXAiLCBnZXRGQyA9IFRSVUUpDQpoZWFkKHJlc3VsdHNfdHJhbnNjcmlwdHMpDQp3cml0ZS50YWJsZShyZXN1bHRzX3RyYW5zY3JpcHRzLCBmaWxlID0gImJhbGxnb3duX3RyYW5zY3JpcHRfcmVzdWx0cy50eHQiLCBzZXAgPSAiXHQiLCBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYpDQpgYGANCg0KDQoNCmBgYHtyfQ0KcmVzdWx0c19nZW5lcyA9IHN0YXR0ZXN0KGJnLCBmZWF0dXJlID0gImdlbmUiLCBtZWFzID0gIkZQS00iLCBjb3ZhcmlhdGUgPSAiZ3JvdXAiLCBnZXRGQyA9IFRSVUUpDQpoZWFkKHJlc3VsdHNfZ2VuZXMpDQp3cml0ZS50YWJsZShyZXN1bHRzX2dlbmVzLCBmaWxlID0gImJhbGxnb3duX2dlbmVfcmVzdWx0cy50eHQiLCBzZXAgPSAiXHQiLCBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYpDQpgYGANCg0KDQojIyBJZGVudGlmeSBhbmQgc29ydCAoaW5jcmVhc2luZykgdGhlIGdlbmVzIGFuZCB0aGUgdHJhbnNjcmlwdHMgYnkgdGhlaXIgcC12YWx1ZXMNCg0KYGBge3J9DQpyZXN1bHRzX2dlbmVzIDwtIGFycmFuZ2UocmVzdWx0c19nZW5lcywgcHZhbCkNCmhlYWQocmVzdWx0c19nZW5lcykNCmBgYA0KDQpgYGB7cn0NCnJlc3VsdHNfdHJhbnNjcmlwdHMgPC0gZGF0YS5mcmFtZShnZW5lSURzPWJhbGxnb3duOjpnZW5lSURzKGJnKSwgcmVzdWx0c190cmFuc2NyaXB0cykNCnJlc3VsdHNfdHJhbnNjcmlwdHMgPC0gYXJyYW5nZShyZXN1bHRzX3RyYW5zY3JpcHRzLCBwdmFsKQ0KaGVhZChyZXN1bHRzX3RyYW5zY3JpcHRzKQ0KYGBgDQoNCg0KIyMgUGxvdCB0aGUgdHJhbnNjcmlwdHMgZm9yIGEgZ2VuZSBhY3Jvc3Mgc2FtcGxlcyANCg0KDQpgYGB7cn0NCnBsb3RUcmFuc2NyaXB0cyhnZW5lID0gIk1TVFJHLjIyODIiLCBnb3duID0gYmcsIHNhbXBsZXMgPSBzYW1wbGVOYW1lcyhiZyksIG1lYXMgPSAiRlBLTSIsIGNvbG9yYnkgPSAidHJhbnNjcmlwdCIsDQogICAgICAgICAgICAgICAgbWFpbiA9ICJ0cmFuc2NyaXB0cyBmcm9tIGdlbmUgTVNUUkcuMjI4MiIpDQpgYGANCg0KIyMgQm94cGxvdCBmb3IgbW9zdCBkaWZmcmVudGlhbGx5IGV4cHJlc3NlZCB0cmFuc2NyaXB0DQoNCmBgYHtyfQ0KaWR4IDwtIHdoaWNoKGdlbmVJRHMoYmcpPT0iTVNUUkcuMjI4MiIpDQppZHgNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdCh0cmFuc2NyaXB0X2Zwa21fbG9nMltpZHgsIF0gfiBwRGF0YShiZykkZ3JvdXAsIGJvcmRlcj1jKDEsIDIpLCBtYWluPXBhc3RlKGJhbGxnb3duOjpnZW5lSURzKGJnKVtpZHhdKSwNCiAgICAgcGNoPTE5LCB4bGFiPSJHcm91cCIsIHlsYWI9ImxvZzIoRlBLTSsxKSIpDQoNCnBvaW50cyh0cmFuc2NyaXB0X2Zwa21fbG9nMltpZHgsXSB+IGppdHRlcihhcy5udW1lcmljKHBEYXRhKGJnKSRncm91cCkpLCBjb2w9YXMubnVtZXJpYyhwRGF0YShiZykkZ3JvdXApLCBwY2g9MjApDQpgYGANCg==