This document illustrates some ways to import annotation data into an RNAseq experiment. It will be reused throughout these analyses and as a result the output may be hidden. If you wish to view it directly: annotation.html

1 Genome annotation input

There are a few methods of importing annotation data into R. The following are two attempts, the second is currently being used in these analyses.

1.1 AnnotationHub: loading OrgDb

AnnotationHub is a newer service and has promise to be an excellent top-level resource for gathering annotation data.

## This doesn't quite work yet
tmp <- sm(library(AnnotationHub))
ah = sm(AnnotationHub())
orgdbs <- sm(query(ah, "OrgDb"))
sc_orgdb <- sm(query(ah, c("OrgDB", "Saccharomyces"))) ##   AH49589 | org.Sc.sgd.db.sqlite
sc_orgdb <- ah[["AH57980"]]
## loading from cache '/home/trey//.AnnotationHub/64726'
class(sc_orgdb)
## [1] "OrgDb"
## attr(,"package")
## [1] "AnnotationDbi"

1.2 Loading a TxDb

OrgDbs provide a set of links between different annotation resources, in the case of yeast that includes GO/KEGG/SGD IDs. We also want links between gene annotations and these gene IDs. The TxDb system provides this information.

please_install("TxDb.Scerevisiae.UCSC.sacCer3.sgdGene")
## [1] 0
tmp <- sm(library(TxDb.Scerevisiae.UCSC.sacCer3.sgdGene))
sc_txdb <- TxDb.Scerevisiae.UCSC.sacCer3.sgdGene

1.3 Loading a genome

There is a non-zero chance we will want to use the actual genome sequence along with these annotations. The BSGenome packages provide that functionality.

tmp <- please_install("BSgenome.Scerevisiae.UCSC.sacCer3")

1.4 Loading from biomart

A completely separate and competing annotation source is biomart.

sc_annotation <- sm(load_biomart_annotations("scerevisiae"))$annotation
sc_ontology <- sm(load_biomart_go("scerevisiae"))$go

1.5 Merging them into an OrganismDb

At this point we have multiple possible ways to mix and match these annotation data. Ideally I would like to put them all into a single format, organismDb is a good choice therefore.

tmp <- sm(library(OrganismDbi))
## The following 2 invocations of makeOrganism do not work because not all the resources are available.
##sc_organismdb <- makeOrganismDbFromBiomart(biomart="ENSEMBL_MART_ENSEMBL", dataset="scerevisiae_gene_ensembl",
##                                           host="dec2015.archive.ensembl.org")
##sc_organismdb <- makeOrganismDbFromTxDb(sc_txdb)

test <- try(library(Sac.cer3))
if (class(test) == "try-error") {
    gd = list(join1 = c(GO.db="GOID", org.Sc.sgd.db="GO"),
              join2 = c(org.Sc.sgd.db="ENTREZID", TxDb.Scerevisiae.UCSC.sacCer3.sgdGene="GENEID"))
    tt <- try(makeOrganismPackage(pkgname="Sac.cer3",  # simplify typing!
                        graphData=gd, organism="Saccharomyces cerevisiae",
                        version="0.0.1", maintainer="atb <abelew@gmail.com>",
                        author="unknown <unknown@genomicsclass.github.io/book/pages/bioc2_rpacks.html>",
                        destDir=".",
                        license="Artistic-2.0"))
    install.packages("Sac.cer3", repos=NULL, type="source")
    test <- try(library(Sac.cer3))
}

1.6 Read a gff file

In contrast, it is possible to load most annotations of interest directly from the gff files used in the alignments.

## The old way of getting genome/annotation data
sc_gff <- "reference/scerevisiae.gff.gz"
sc_fasta <- "reference/scerevisiae.fasta.xz"
sc_gff_annotations <- sm(load_gff_annotations(sc_gff, type="gene"))
rownames(sc_gff_annotations) <- make.names(sc_gff_annotations$transcript_name, unique=TRUE)

2 Putting the pieces together

The following block sets up a master experiment containing one set of anontations and all the reads. Note that the following is specific to the previous (version 1) set of data.

sc_annotation[["fwd_location"]] <- paste0(sc_annotation[["chromosome"]], "_", sc_annotation[["start"]])
sc_annotation[["rev_location"]] <- paste0(sc_annotation[["chromosome"]], "_", sc_annotation[["end"]])
sc_gff_annotations[["fwd_location"]] <- paste0(sc_gff_annotations[["seqnames"]], "_", sc_gff_annotations[["start"]])
sc_gff_annotations[["rev_location"]] <- paste0(sc_gff_annotations[["seqnames"]], "_", sc_gff_annotations[["end"]])
sc_gff_annotations[["gff_rowname"]] <- rownames(sc_gff_annotations)
sc_fwd_annotations <- merge(sc_annotation, sc_gff_annotations, by="fwd_location")
sc_rev_annotations <- merge(sc_annotation, sc_gff_annotations, by="rev_location")
colnames(sc_fwd_annotations) <- c("location","transcriptID","geneID", "Description",
                                  "Type", "length", "chromosome", "strand", "start",
                                  "end", "location.x", "seqnames",
                                  "start.y", "end.y", "width", "strand.y", "source", "type",
                                  "score", "phase", "exon_number", "gene_id", "ID", "p_id",
                                  "protein_id", "transcript_id", "transcript_name", "tss_id",
                                  "seqedit", "location.y", "gff_rowname")
colnames(sc_rev_annotations) <- colnames(sc_fwd_annotations)
sc_all_annotations <- rbind(sc_fwd_annotations, sc_rev_annotations)
rownames(sc_all_annotations) <- make.names(sc_all_annotations[["gff_rowname"]], unique=TRUE)
sc_all_annotations <- sc_all_annotations[, c("transcriptID","geneID","Description","Type","length","chromosome","strand","start","end","tss_id")]
colnames(sc_all_annotations) <- c("transcriptID","geneID","Description","Type","length","chromosome","strand","start","end","tss_id")
sc_all_annotations[["location"]] <- paste0(sc_all_annotations[["chromosome"]], "_", sc_all_annotations[["start"]], "_", sc_all_annotations[["end"]])

sc_expt <- sm(create_expt("all_samples.csv", gene_info=sc_gff_annotations))
dim(Biobase::exprs(sc_expt$expressionset))
## [1] 6691   12
knitr::kable(head(Biobase::fData(sc_expt$expressionset)))
seqnames start end width strand source type score phase exon_number gene_id ID p_id protein_id transcript_id transcript_name tss_id seqedit fwd_location rev_location gff_rowname
AAC1 XIII 387318 388244 927 - protein_coding gene undefined 0 1 YMR056C AAC1 P3747 YMR056C YMR056C AAC1 TSS5132 undefined XIII_387318 XIII_388244 AAC1
AAC3 II 415983 416903 921 + protein_coding gene undefined 0 1 YBR085W AAC3 P443 YBR085W YBR085W AAC3 TSS1609 undefined II_415983 II_416903 AAC3
AAD10 X 727405 728268 864 + protein_coding gene undefined 0 1 YJR155W AAD10 P1106 YJR155W YJR155W AAD10 TSS5024 undefined X_727405 X_728268 AAD10
AAD14 XIV 16121 17248 1128 - protein_coding gene undefined 0 1 YNL331C AAD14 P3139 YNL331C YNL331C AAD14 TSS6941 undefined XIV_16121 XIV_17248 AAD14
AAD15 XV 1650 2078 429 - protein_coding gene undefined 0 1 YOL165C AAD15 P1525 YOL165C YOL165C AAD15 TSS108 undefined XV_1650 XV_2078 AAD15
AAD16 VI 14308 14763 456 - protein_coding gene undefined 0 1 YFL057C AAD16 P4716 YFL057C YFL057C AAD16 TSS2145 undefined VI_14308 VI_14763 AAD16
exo_expt <- sm(create_expt("all_samples_merged.csv", gene_info=sc_gff_annotations))
v3_expt <- create_expt("sample_sheets/all_samples.xlsx", gene_info=sc_gff_annotations, file_column="bt2file")
## Reading the sample metadata.
## The sample definitions comprises: 28, 18 rows, columns.
## Reading count tables.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0774/outputs/bowtie2_scerevisiae/hpgl0774_forward-trimmed.count.xz contains 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0775/outputs/bowtie2_scerevisiae/hpgl0775_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0776/outputs/bowtie2_scerevisiae/hpgl0776_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0777/outputs/bowtie2_scerevisiae/hpgl0777_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0778/outputs/bowtie2_scerevisiae/hpgl0778_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0779/outputs/bowtie2_scerevisiae/hpgl0779_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0780/outputs/bowtie2_scerevisiae/hpgl0780_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0781/outputs/bowtie2_scerevisiae/hpgl0781_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0782/outputs/bowtie2_scerevisiae/hpgl0782_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0783/outputs/bowtie2_scerevisiae/hpgl0783_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0784/outputs/bowtie2_scerevisiae/hpgl0784_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0785/outputs/bowtie2_scerevisiae/hpgl0785_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0786/outputs/bowtie2_scerevisiae/hpgl0786_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0787/outputs/bowtie2_scerevisiae/hpgl0787_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0788/outputs/bowtie2_scerevisiae/hpgl0788_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## /cbcb/nelsayed-scratch/atb/rnaseq/scerevisiae_cbf5_2015/preprocessing/v2/hpgl0789/outputs/bowtie2_scerevisiae/hpgl0789_forward-trimmed.count.xz contains 7131 rows and merges to 7131 rows.
## Finished reading count tables.
## Matched 6692 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
library(biomaRt)
int_mart <- useMart(biomart="ENSEMBL_MART_ENSEMBL", host="dec2015.archive.ensembl.org")
int_ensembl <- try(biomaRt::useDataset("scerevisiae_gene_ensembl", mart=int_mart))
int_search <- getBM(attributes=c("ensembl_gene_id", "ensembl_exon_id", "transcript_biotype",
                                 "transcript_start", "transcript_end", "transcript_length"), mart=int_ensembl)

multi_exons <- grepl(pattern="\\.2", x=int_search[["ensembl_exon_id"]])
multi_exons <- int_search[multi_exons, ]

multi_annots <- int_search[["ensembl_gene_id"]] %in% multi_exons[["ensembl_gene_id"]]
multi_annots <- int_search[multi_annots, ]
## Damn it sets the same stop/start for all exons and same length, that is dumb.
head(multi_annots)
##    ensembl_gene_id ensembl_exon_id transcript_biotype transcript_start transcript_end
## 7          YPR098C       YPR098C.1     protein_coding           728947         729528
## 8          YPR098C       YPR098C.2     protein_coding           728947         729528
## 50         YDR305C       YDR305C.1     protein_coding          1072746        1073488
## 51         YDR305C       YDR305C.2     protein_coding          1072746        1073488
## 75         YPR187W       YPR187W.1     protein_coding           911257         911800
## 76         YPR187W       YPR187W.2     protein_coding           911257         911800
##    transcript_length
## 7                486
## 8                486
## 50               654
## 51               654
## 75               468
## 76               468
## The set of all intron-containing CDS yeast genes.  However I have not found definitive
## start/ends for the introns.

At this point, we should have everything necessary to play!

if (!isTRUE(get0("skip_load"))) {
  pander::pander(sessionInfo())
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
  message(paste0("Saving to ", this_save))
  tmp <- sm(saveme(filename=this_save))
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 5d8c266e48bb9f73cdac8300e5c7c9f5baf003dc
## R> packrat::restore()
## This is hpgltools commit: Wed Mar 21 15:55:32 2018 -0400: 5d8c266e48bb9f73cdac8300e5c7c9f5baf003dc
## Saving to annotation-v20151102.rda.xz
LS0tCnRpdGxlOiAiUy5jZXJldmlzaWFlIDIwMTU6IEFubm90YXRpb24uIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogIGNvZGVfZG93bmxvYWQ6IHRydWUKICBjb2RlX2ZvbGRpbmc6IHNob3cKICBmaWdfY2FwdGlvbjogdHJ1ZQogIGZpZ19oZWlnaHQ6IDcKICBmaWdfd2lkdGg6IDcKICBoaWdobGlnaHQ6IGRlZmF1bHQKICBrZWVwX21kOiBmYWxzZQogIG1vZGU6IHNlbGZjb250YWluZWQKICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogIHRoZW1lOiByZWFkYWJsZQogIHRvYzogdHJ1ZQogIHRvY19mbG9hdDoKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIGxpYnJhcnkoaHBnbHRvb2xzKQogIHR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQogIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKICBrbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQogIG9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCiAgZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCiAgdmVyIDwtICIyMDE1MTEwMiIKICBwcmV2aW91c19maWxlIDwtICJpbmRleC5SbWQiCgogIHRtcCA8LSB0cnkoc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpKQogIHJtZF9maWxlIDwtICJhbm5vdGF0aW9uLlJtZCIKfQpgYGAKClRoaXMgZG9jdW1lbnQgaWxsdXN0cmF0ZXMgc29tZSB3YXlzIHRvIGltcG9ydCBhbm5vdGF0aW9uIGRhdGEgaW50byBhbiBSTkFzZXEgZXhwZXJpbWVudC4gIEl0IHdpbGwgYmUKcmV1c2VkIHRocm91Z2hvdXQgdGhlc2UgYW5hbHlzZXMgYW5kIGFzIGEgcmVzdWx0IHRoZSBvdXRwdXQgbWF5IGJlIGhpZGRlbi4gIElmIHlvdSB3aXNoIHRvIHZpZXcgaXQKZGlyZWN0bHk6ICBbYW5ub3RhdGlvbi5odG1sXShhbm5vdGF0aW9uLmh0bWwpCgojIEdlbm9tZSBhbm5vdGF0aW9uIGlucHV0CgpUaGVyZSBhcmUgYSBmZXcgbWV0aG9kcyBvZiBpbXBvcnRpbmcgYW5ub3RhdGlvbiBkYXRhIGludG8gUi4gIFRoZSBmb2xsb3dpbmcgYXJlIHR3byBhdHRlbXB0cywgdGhlCnNlY29uZCBpcyBjdXJyZW50bHkgYmVpbmcgdXNlZCBpbiB0aGVzZSBhbmFseXNlcy4KCiMjIEFubm90YXRpb25IdWI6IGxvYWRpbmcgT3JnRGIKCkFubm90YXRpb25IdWIgaXMgYSBuZXdlciBzZXJ2aWNlIGFuZCBoYXMgcHJvbWlzZSB0byBiZSBhbiBleGNlbGxlbnQgdG9wLWxldmVsIHJlc291cmNlIGZvciBnYXRoZXJpbmcKYW5ub3RhdGlvbiBkYXRhLgoKYGBge3IgZGF0YV9pbnB1dF9nZW5vbWV9CiMjIFRoaXMgZG9lc24ndCBxdWl0ZSB3b3JrIHlldAp0bXAgPC0gc20obGlicmFyeShBbm5vdGF0aW9uSHViKSkKYWggPSBzbShBbm5vdGF0aW9uSHViKCkpCm9yZ2RicyA8LSBzbShxdWVyeShhaCwgIk9yZ0RiIikpCnNjX29yZ2RiIDwtIHNtKHF1ZXJ5KGFoLCBjKCJPcmdEQiIsICJTYWNjaGFyb215Y2VzIikpKSAjIyAgIEFINDk1ODkgfCBvcmcuU2Muc2dkLmRiLnNxbGl0ZQpzY19vcmdkYiA8LSBhaFtbIkFINTc5ODAiXV0KY2xhc3Moc2Nfb3JnZGIpCmBgYAoKIyMgTG9hZGluZyBhIFR4RGIKCk9yZ0RicyBwcm92aWRlIGEgc2V0IG9mIGxpbmtzIGJldHdlZW4gZGlmZmVyZW50IGFubm90YXRpb24gcmVzb3VyY2VzLCBpbiB0aGUgY2FzZSBvZiB5ZWFzdCB0aGF0CmluY2x1ZGVzIEdPL0tFR0cvU0dEIElEcy4gIFdlIGFsc28gd2FudCBsaW5rcyBiZXR3ZWVuIGdlbmUgYW5ub3RhdGlvbnMgYW5kIHRoZXNlIGdlbmUgSURzLiAgVGhlIFR4RGIKc3lzdGVtIHByb3ZpZGVzIHRoaXMgaW5mb3JtYXRpb24uCgpgYGB7ciBzY2VyZXZpc2lhZV90eGRifQpwbGVhc2VfaW5zdGFsbCgiVHhEYi5TY2VyZXZpc2lhZS5VQ1NDLnNhY0NlcjMuc2dkR2VuZSIpCnRtcCA8LSBzbShsaWJyYXJ5KFR4RGIuU2NlcmV2aXNpYWUuVUNTQy5zYWNDZXIzLnNnZEdlbmUpKQpzY190eGRiIDwtIFR4RGIuU2NlcmV2aXNpYWUuVUNTQy5zYWNDZXIzLnNnZEdlbmUKYGBgCgojIyBMb2FkaW5nIGEgZ2Vub21lCgpUaGVyZSBpcyBhIG5vbi16ZXJvIGNoYW5jZSB3ZSB3aWxsIHdhbnQgdG8gdXNlIHRoZSBhY3R1YWwgZ2Vub21lIHNlcXVlbmNlIGFsb25nIHdpdGggdGhlc2UKYW5ub3RhdGlvbnMuICBUaGUgQlNHZW5vbWUgcGFja2FnZXMgcHJvdmlkZSB0aGF0IGZ1bmN0aW9uYWxpdHkuCgpgYGB7ciBzY2VyZXZpc2lhZV9ic2dlbm9tZX0KdG1wIDwtIHBsZWFzZV9pbnN0YWxsKCJCU2dlbm9tZS5TY2VyZXZpc2lhZS5VQ1NDLnNhY0NlcjMiKQpgYGAKCiMjIExvYWRpbmcgZnJvbSBiaW9tYXJ0CgpBIGNvbXBsZXRlbHkgc2VwYXJhdGUgYW5kIGNvbXBldGluZyBhbm5vdGF0aW9uIHNvdXJjZSBpcyBiaW9tYXJ0LgoKYGBge3Igc2NlcmV2aXNpYWVfYmlvbWFydH0Kc2NfYW5ub3RhdGlvbiA8LSBzbShsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoInNjZXJldmlzaWFlIikpJGFubm90YXRpb24Kc2Nfb250b2xvZ3kgPC0gc20obG9hZF9iaW9tYXJ0X2dvKCJzY2VyZXZpc2lhZSIpKSRnbwpgYGAKCiMjIE1lcmdpbmcgdGhlbSBpbnRvIGFuIE9yZ2FuaXNtRGIKCkF0IHRoaXMgcG9pbnQgd2UgaGF2ZSBtdWx0aXBsZSBwb3NzaWJsZSB3YXlzIHRvIG1peCBhbmQgbWF0Y2ggdGhlc2UgYW5ub3RhdGlvbiBkYXRhLiAgSWRlYWxseSBJCndvdWxkIGxpa2UgdG8gcHV0IHRoZW0gYWxsIGludG8gYSBzaW5nbGUgZm9ybWF0LCBvcmdhbmlzbURiIGlzIGEgZ29vZCBjaG9pY2UgdGhlcmVmb3JlLgoKYGBge3Igb3JnYW5pc21kYn0KdG1wIDwtIHNtKGxpYnJhcnkoT3JnYW5pc21EYmkpKQojIyBUaGUgZm9sbG93aW5nIDIgaW52b2NhdGlvbnMgb2YgbWFrZU9yZ2FuaXNtIGRvIG5vdCB3b3JrIGJlY2F1c2Ugbm90IGFsbCB0aGUgcmVzb3VyY2VzIGFyZSBhdmFpbGFibGUuCiMjc2Nfb3JnYW5pc21kYiA8LSBtYWtlT3JnYW5pc21EYkZyb21CaW9tYXJ0KGJpb21hcnQ9IkVOU0VNQkxfTUFSVF9FTlNFTUJMIiwgZGF0YXNldD0ic2NlcmV2aXNpYWVfZ2VuZV9lbnNlbWJsIiwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG9zdD0iZGVjMjAxNS5hcmNoaXZlLmVuc2VtYmwub3JnIikKIyNzY19vcmdhbmlzbWRiIDwtIG1ha2VPcmdhbmlzbURiRnJvbVR4RGIoc2NfdHhkYikKCnRlc3QgPC0gdHJ5KGxpYnJhcnkoU2FjLmNlcjMpKQppZiAoY2xhc3ModGVzdCkgPT0gInRyeS1lcnJvciIpIHsKICAgIGdkID0gbGlzdChqb2luMSA9IGMoR08uZGI9IkdPSUQiLCBvcmcuU2Muc2dkLmRiPSJHTyIpLAogICAgICAgICAgICAgIGpvaW4yID0gYyhvcmcuU2Muc2dkLmRiPSJFTlRSRVpJRCIsIFR4RGIuU2NlcmV2aXNpYWUuVUNTQy5zYWNDZXIzLnNnZEdlbmU9IkdFTkVJRCIpKQogICAgdHQgPC0gdHJ5KG1ha2VPcmdhbmlzbVBhY2thZ2UocGtnbmFtZT0iU2FjLmNlcjMiLCAgIyBzaW1wbGlmeSB0eXBpbmchCiAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoRGF0YT1nZCwgb3JnYW5pc209IlNhY2NoYXJvbXljZXMgY2VyZXZpc2lhZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnNpb249IjAuMC4xIiwgbWFpbnRhaW5lcj0iYXRiIDxhYmVsZXdAZ21haWwuY29tPiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1dGhvcj0idW5rbm93biA8dW5rbm93bkBnZW5vbWljc2NsYXNzLmdpdGh1Yi5pby9ib29rL3BhZ2VzL2Jpb2MyX3JwYWNrcy5odG1sPiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlc3REaXI9Ii4iLAogICAgICAgICAgICAgICAgICAgICAgICBsaWNlbnNlPSJBcnRpc3RpYy0yLjAiKSkKICAgIGluc3RhbGwucGFja2FnZXMoIlNhYy5jZXIzIiwgcmVwb3M9TlVMTCwgdHlwZT0ic291cmNlIikKICAgIHRlc3QgPC0gdHJ5KGxpYnJhcnkoU2FjLmNlcjMpKQp9CmBgYAoKIyMgUmVhZCBhIGdmZiBmaWxlCgpJbiBjb250cmFzdCwgaXQgaXMgcG9zc2libGUgdG8gbG9hZCBtb3N0IGFubm90YXRpb25zIG9mIGludGVyZXN0IGRpcmVjdGx5IGZyb20gdGhlIGdmZiBmaWxlcyB1c2VkIGluCnRoZSBhbGlnbm1lbnRzLgoKYGBge3IgZ2Vub21lX2lucHV0fQojIyBUaGUgb2xkIHdheSBvZiBnZXR0aW5nIGdlbm9tZS9hbm5vdGF0aW9uIGRhdGEKc2NfZ2ZmIDwtICJyZWZlcmVuY2Uvc2NlcmV2aXNpYWUuZ2ZmLmd6IgpzY19mYXN0YSA8LSAicmVmZXJlbmNlL3NjZXJldmlzaWFlLmZhc3RhLnh6IgpzY19nZmZfYW5ub3RhdGlvbnMgPC0gc20obG9hZF9nZmZfYW5ub3RhdGlvbnMoc2NfZ2ZmLCB0eXBlPSJnZW5lIikpCnJvd25hbWVzKHNjX2dmZl9hbm5vdGF0aW9ucykgPC0gbWFrZS5uYW1lcyhzY19nZmZfYW5ub3RhdGlvbnMkdHJhbnNjcmlwdF9uYW1lLCB1bmlxdWU9VFJVRSkKYGBgCgojIFB1dHRpbmcgdGhlIHBpZWNlcyB0b2dldGhlcgoKVGhlIGZvbGxvd2luZyBibG9jayBzZXRzIHVwIGEgbWFzdGVyIGV4cGVyaW1lbnQgY29udGFpbmluZyBvbmUgc2V0IG9mIGFub250YXRpb25zIGFuZCBhbGwgdGhlIHJlYWRzLgpOb3RlIHRoYXQgdGhlIGZvbGxvd2luZyBpcyBzcGVjaWZpYyB0byB0aGUgcHJldmlvdXMgKHZlcnNpb24gMSkgc2V0IG9mIGRhdGEuCgpgYGB7ciBleHBlcmltZW50YWxfZGVzaWdufQpzY19hbm5vdGF0aW9uW1siZndkX2xvY2F0aW9uIl1dIDwtIHBhc3RlMChzY19hbm5vdGF0aW9uW1siY2hyb21vc29tZSJdXSwgIl8iLCBzY19hbm5vdGF0aW9uW1sic3RhcnQiXV0pCnNjX2Fubm90YXRpb25bWyJyZXZfbG9jYXRpb24iXV0gPC0gcGFzdGUwKHNjX2Fubm90YXRpb25bWyJjaHJvbW9zb21lIl1dLCAiXyIsIHNjX2Fubm90YXRpb25bWyJlbmQiXV0pCnNjX2dmZl9hbm5vdGF0aW9uc1tbImZ3ZF9sb2NhdGlvbiJdXSA8LSBwYXN0ZTAoc2NfZ2ZmX2Fubm90YXRpb25zW1sic2VxbmFtZXMiXV0sICJfIiwgc2NfZ2ZmX2Fubm90YXRpb25zW1sic3RhcnQiXV0pCnNjX2dmZl9hbm5vdGF0aW9uc1tbInJldl9sb2NhdGlvbiJdXSA8LSBwYXN0ZTAoc2NfZ2ZmX2Fubm90YXRpb25zW1sic2VxbmFtZXMiXV0sICJfIiwgc2NfZ2ZmX2Fubm90YXRpb25zW1siZW5kIl1dKQpzY19nZmZfYW5ub3RhdGlvbnNbWyJnZmZfcm93bmFtZSJdXSA8LSByb3duYW1lcyhzY19nZmZfYW5ub3RhdGlvbnMpCnNjX2Z3ZF9hbm5vdGF0aW9ucyA8LSBtZXJnZShzY19hbm5vdGF0aW9uLCBzY19nZmZfYW5ub3RhdGlvbnMsIGJ5PSJmd2RfbG9jYXRpb24iKQpzY19yZXZfYW5ub3RhdGlvbnMgPC0gbWVyZ2Uoc2NfYW5ub3RhdGlvbiwgc2NfZ2ZmX2Fubm90YXRpb25zLCBieT0icmV2X2xvY2F0aW9uIikKY29sbmFtZXMoc2NfZndkX2Fubm90YXRpb25zKSA8LSBjKCJsb2NhdGlvbiIsInRyYW5zY3JpcHRJRCIsImdlbmVJRCIsICJEZXNjcmlwdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHlwZSIsICJsZW5ndGgiLCAiY2hyb21vc29tZSIsICJzdHJhbmQiLCAic3RhcnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImVuZCIsICJsb2NhdGlvbi54IiwgInNlcW5hbWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdGFydC55IiwgImVuZC55IiwgIndpZHRoIiwgInN0cmFuZC55IiwgInNvdXJjZSIsICJ0eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzY29yZSIsICJwaGFzZSIsICJleG9uX251bWJlciIsICJnZW5lX2lkIiwgIklEIiwgInBfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByb3RlaW5faWQiLCAidHJhbnNjcmlwdF9pZCIsICJ0cmFuc2NyaXB0X25hbWUiLCAidHNzX2lkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZXFlZGl0IiwgImxvY2F0aW9uLnkiLCAiZ2ZmX3Jvd25hbWUiKQpjb2xuYW1lcyhzY19yZXZfYW5ub3RhdGlvbnMpIDwtIGNvbG5hbWVzKHNjX2Z3ZF9hbm5vdGF0aW9ucykKc2NfYWxsX2Fubm90YXRpb25zIDwtIHJiaW5kKHNjX2Z3ZF9hbm5vdGF0aW9ucywgc2NfcmV2X2Fubm90YXRpb25zKQpyb3duYW1lcyhzY19hbGxfYW5ub3RhdGlvbnMpIDwtIG1ha2UubmFtZXMoc2NfYWxsX2Fubm90YXRpb25zW1siZ2ZmX3Jvd25hbWUiXV0sIHVuaXF1ZT1UUlVFKQpzY19hbGxfYW5ub3RhdGlvbnMgPC0gc2NfYWxsX2Fubm90YXRpb25zWywgYygidHJhbnNjcmlwdElEIiwiZ2VuZUlEIiwiRGVzY3JpcHRpb24iLCJUeXBlIiwibGVuZ3RoIiwiY2hyb21vc29tZSIsInN0cmFuZCIsInN0YXJ0IiwiZW5kIiwidHNzX2lkIildCmNvbG5hbWVzKHNjX2FsbF9hbm5vdGF0aW9ucykgPC0gYygidHJhbnNjcmlwdElEIiwiZ2VuZUlEIiwiRGVzY3JpcHRpb24iLCJUeXBlIiwibGVuZ3RoIiwiY2hyb21vc29tZSIsInN0cmFuZCIsInN0YXJ0IiwiZW5kIiwidHNzX2lkIikKc2NfYWxsX2Fubm90YXRpb25zW1sibG9jYXRpb24iXV0gPC0gcGFzdGUwKHNjX2FsbF9hbm5vdGF0aW9uc1tbImNocm9tb3NvbWUiXV0sICJfIiwgc2NfYWxsX2Fubm90YXRpb25zW1sic3RhcnQiXV0sICJfIiwgc2NfYWxsX2Fubm90YXRpb25zW1siZW5kIl1dKQoKc2NfZXhwdCA8LSBzbShjcmVhdGVfZXhwdCgiYWxsX3NhbXBsZXMuY3N2IiwgZ2VuZV9pbmZvPXNjX2dmZl9hbm5vdGF0aW9ucykpCmRpbShCaW9iYXNlOjpleHBycyhzY19leHB0JGV4cHJlc3Npb25zZXQpKQprbml0cjo6a2FibGUoaGVhZChCaW9iYXNlOjpmRGF0YShzY19leHB0JGV4cHJlc3Npb25zZXQpKSkKZXhvX2V4cHQgPC0gc20oY3JlYXRlX2V4cHQoImFsbF9zYW1wbGVzX21lcmdlZC5jc3YiLCBnZW5lX2luZm89c2NfZ2ZmX2Fubm90YXRpb25zKSkKdjNfZXhwdCA8LSBjcmVhdGVfZXhwdCgic2FtcGxlX3NoZWV0cy9hbGxfc2FtcGxlcy54bHN4IiwgZ2VuZV9pbmZvPXNjX2dmZl9hbm5vdGF0aW9ucywgZmlsZV9jb2x1bW49ImJ0MmZpbGUiKQpgYGAKCmBgYHtyIGdldF9pbnRyb25zfQpsaWJyYXJ5KGJpb21hUnQpCmludF9tYXJ0IDwtIHVzZU1hcnQoYmlvbWFydD0iRU5TRU1CTF9NQVJUX0VOU0VNQkwiLCBob3N0PSJkZWMyMDE1LmFyY2hpdmUuZW5zZW1ibC5vcmciKQppbnRfZW5zZW1ibCA8LSB0cnkoYmlvbWFSdDo6dXNlRGF0YXNldCgic2NlcmV2aXNpYWVfZ2VuZV9lbnNlbWJsIiwgbWFydD1pbnRfbWFydCkpCmludF9zZWFyY2ggPC0gZ2V0Qk0oYXR0cmlidXRlcz1jKCJlbnNlbWJsX2dlbmVfaWQiLCAiZW5zZW1ibF9leG9uX2lkIiwgInRyYW5zY3JpcHRfYmlvdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cmFuc2NyaXB0X3N0YXJ0IiwgInRyYW5zY3JpcHRfZW5kIiwgInRyYW5zY3JpcHRfbGVuZ3RoIiksIG1hcnQ9aW50X2Vuc2VtYmwpCgptdWx0aV9leG9ucyA8LSBncmVwbChwYXR0ZXJuPSJcXC4yIiwgeD1pbnRfc2VhcmNoW1siZW5zZW1ibF9leG9uX2lkIl1dKQptdWx0aV9leG9ucyA8LSBpbnRfc2VhcmNoW211bHRpX2V4b25zLCBdCgptdWx0aV9hbm5vdHMgPC0gaW50X3NlYXJjaFtbImVuc2VtYmxfZ2VuZV9pZCJdXSAlaW4lIG11bHRpX2V4b25zW1siZW5zZW1ibF9nZW5lX2lkIl1dCm11bHRpX2Fubm90cyA8LSBpbnRfc2VhcmNoW211bHRpX2Fubm90cywgXQojIyBEYW1uIGl0IHNldHMgdGhlIHNhbWUgc3RvcC9zdGFydCBmb3IgYWxsIGV4b25zIGFuZCBzYW1lIGxlbmd0aCwgdGhhdCBpcyBkdW1iLgpoZWFkKG11bHRpX2Fubm90cykKIyMgVGhlIHNldCBvZiBhbGwgaW50cm9uLWNvbnRhaW5pbmcgQ0RTIHllYXN0IGdlbmVzLiAgSG93ZXZlciBJIGhhdmUgbm90IGZvdW5kIGRlZmluaXRpdmUKIyMgc3RhcnQvZW5kcyBmb3IgdGhlIGludHJvbnMuCmBgYAoKQXQgdGhpcyBwb2ludCwgd2Ugc2hvdWxkIGhhdmUgZXZlcnl0aGluZyBuZWNlc3NhcnkgdG8gcGxheSEKCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCn0KYGBgCg==