This is documents shows the quality control of dataset scRNA-seq data from human glioblastoma cells and gliomasphere cell lines.
Load packages
library('ggplot2')
library('rtracklayer')
require(gplots)
library(plyr)
library(reshape2)
library(scater)
library(knitr)
options(stringsAsFactors = FALSE)
Load annotation
gtf_gencode <- readGFF("~/Documents/HCA/reference/gencode.v27.primary_assembly.annotation.gtf", version=2L, tags = c("gene_name","gene_id", "transcript_id","gene_type"))
genes<-subset(gtf_gencode,gtf_gencode$type == "gene")
Load dataset. All outputs of pipeline,include metrics and quantification have been saved in a Rdata.
load('hisat2_outputs_bundle.RData')
Sequencing Data QC
General quality control with sequencing data
Basecall Quality Distribution
The mean quality value across each base position in the read.
m.qual<-melt(hisat2.basequality,id="Bin")
p<-ggplot(m.qual,aes(x=Bin,y=value,group=variable,color=value))+geom_point()+geom_line()
p<-p+ scale_colour_gradientn(colours = rainbow(10))
pngfile<-paste('./images/base_quality_50bp_hisat2.png',sep='')
myimages<-pngfile
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(myimages)
Basecall Distribution
The proportion of each base position for which each of the four normal DNA bases and a missing base has been called.
colnames(hisat2.basecall)
[1] "sraID" "READ_END" "CYCLE" "PCT_A" "PCT_C" "PCT_G" "PCT_T" "PCT_N"
b50<-names(which(table(hisat2.basecall$sraID)==50))
dd<-subset(hisat2.basecall,hisat2.basecall$sraID %in% b50)
m.bc<-melt(dd,id=c('sraID','READ_END','CYCLE'))
p<-ggplot(m.bc,aes(x=CYCLE,y=value,group=interaction(sraID,READ_END),color=variable))+geom_line()+facet_grid(variable~.)
pngfile<-paste('./images/basecall_50bp_hisat2.png',sep='')
myimages<-pngfile
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(myimages)
Alignment Statistics
Two Picard metrics provide main alignment QC metrics, MarkDuplication
and CollectAlignmentMetrics
.
colnames(hisat2.aln)
colnames(hisat2.dup)
Alignment Bias within Pairs
Compare alignment rate of R1
and R2
r1<-subset(hisat2.aln,hisat2.aln$CATEGORY == "FIRST_OF_PAIR")
r2<-subset(hisat2.aln,hisat2.aln$CATEGORY=="SECOND_OF_PAIR")
dd<-data.frame('sraID'=r1$sraID,'R1'=r1$PCT_PF_READS_ALIGNED,'R2'=r2$PCT_PF_READS_ALIGNED)
mlist<-match(dd$sraID,metadata$Run_s)
metadata<-metadata[mlist,] ## match metadat with metrics file
p<-ggplot(dd,aes(x=R1,y=R2,color=as.factor(metadata$AvgSpotLen_l)))+geom_point()
p<-p+geom_abline(intercept=0, slope=1,color='blue')
pngfile<-paste('./images/hisat2_R1_R2_PCT_PF_READS_ALIGNED.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
Aligned, multiple aligned, unmapped
Aligned vs unmapped.
unq.rds<-as.numeric(hisat2.logs[3,-1])*2+as.numeric(hisat2.logs[8,-1])+as.numeric(hisat2.logs[5,-1])*2
mult.rds<-as.numeric(hisat2.logs[4,-1])*2+as.numeric(hisat2.logs[9,-1])
aln.rds<-unq.rds+mult.rds
unq.pct<-unq.rds/aln.rds
mult.pct<-mult.rds/aln.rds
dd<-data.frame('sraID'=colnames(hisat2.logs)[-1],'multi-mapping'=mult.pct,'uniq-mapping'=unq.pct)
mdd<-melt(dd)
Using sraID as id variables
p<-ggplot(mdd, aes(x = sraID,y = value)) + geom_area(aes(fill=variable,group=variable), position='stack')
pngfile<-paste('./images/hisat2_aln_secondary_primary_PCT_Stacking.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
Uniquely vs multiple mapping reads
unq.rds<-as.numeric(hisat2.logs[3,-1])*2+as.numeric(hisat2.logs[8,-1])+as.numeric(hisat2.logs[5,-1])*2
mult.rds<-as.numeric(hisat2.logs[4,-1])*2+as.numeric(hisat2.logs[9,-1])
aln.rds<-unq.rds+mult.rds
unq.pct<-unq.rds/aln.rds
mult.pct<-mult.rds/aln.rds
dd<-data.frame('sraID'=colnames(hisat2.logs)[-1],'multi-mapping'=mult.pct,'uniq-mapping'=unq.pct)
mdd<-melt(dd)
Using sraID as id variables
p<-ggplot(mdd, aes(x = sraID,y = value)) + geom_area(aes(fill=variable,group=variable), position='stack')
pngfile<-paste('./images/hisat2_aln_secondary_primary_PCT_Stacking.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
RNA QC metrics
RNA metrics
colnames(hisat2.rna)
We report PCT_RIBOSOMAL_BASES
,PCT_CODING_BASES
,PCT_UTR_BASES
,PCT_INTRONIC_BASES
and PCT_INTERGENIC_BASES
##extract metrics
rna<-hisat2.rna[,c('sraID','PCT_INTERGENIC_BASES','PCT_INTRONIC_BASES','PCT_UTR_BASES','PCT_CODING_BASES','PCT_RIBOSOMAL_BASES')]
rna.m<-melt(rna)
Using sraID as id variables
p<-ggplot(rna.m, aes(x = sraID,y = value)) + geom_area(aes(fill=variable,group = variable), position='stack')
pngfile<-paste('./images/hisat2_RNA_PCT_Stacking.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
Another metrics we would like to show is the All_Reads.normalized_coverage
alone transcripts and normalized by GC-content. Picard first bin transcripts from 3` to 5’ and then reports this metrics by calculating reads counts in each bin along transcripts
cov.m<-melt(hisat2.coverage,id='Bin')
mlist<-match(cov.m$variable,metadata$Run_s)
mdata<-metadata$source_name_s[mlist]
cov.m<-data.frame(cov.m,'cell'=mdata)
p<-ggplot(cov.m,aes(x=Bin,y=value,group=interaction(variable,cell),color=cell))+geom_line()+facet_grid(cell~.)+scale_y_log10()
pngfile<-paste('./images/hisat2_RNA_coverage.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
Quantification QC
We can define detected genes
by require the reads count of the gene to be at least >5
##dim(hisat2rsem.cnt)
cnt.dd<-hisat2rsem.cnt[,-1]
## total reads aln
cnt.tot<-apply(cnt.dd,2,sum)
## total gene reads count
cnt.gene<-apply(cnt.dd,2,function(x){sum(x>5)})
## mt genes
x<-subset(cnt.dd,hisat2rsem.cnt$ensID %in% mt.genes$gene_id)
##mt gene read counts
cnt.mt<-apply(x,2,sum)
## create df
dd<-data.frame('sraID'=colnames(dd),'readCounts'=cnt.tot,'mt'=cnt.mt,'detectedGenes'=cnt.gene)
Reads Counts saturation plots
p<-ggplot(dd,aes(x=readCounts,y=detectedGenes,color=detectedGenes))+geom_point()+scale_x_log10()+scale_y_log10()
pngfile<-paste('./images/hisat2_gene_count_saturation.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
mt gene coverage
p<-ggplot(dd,aes(x=cnt.mt/readCounts))+geom_histogram()+xlab('% in MT genes')
pngfile<-paste('./images/hisat2_mt_gene_count.png',sep='')
ggsave(plot=p,file=pngfile,type='cairo-png',width=10,height=10)
include_graphics(pngfile)
LS0tCnRpdGxlOiAic2NSTkEtU2VxIFFDIFJlcG9ydCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBkb2N1bWVudHMgc2hvd3MgdGhlIHF1YWxpdHkgY29udHJvbCBvZiBkYXRhc2V0IHNjUk5BLXNlcSBbZGF0YV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9iaW9wcm9qZWN0L1BSSk5BMjQ4MzAyKSBmcm9tIGh1bWFuIGdsaW9ibGFzdG9tYSBjZWxscyBhbmQgZ2xpb21hc3BoZXJlIGNlbGwgbGluZXMuCgpMb2FkIHBhY2thZ2VzCgpgYGB7cn0KbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ3J0cmFja2xheWVyJykKcmVxdWlyZShncGxvdHMpIApsaWJyYXJ5KHBseXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoc2NhdGVyKQpsaWJyYXJ5KGtuaXRyKQpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCkxvYWQgYW5ub3RhdGlvbgpgYGB7cn0KZ3RmX2dlbmNvZGUgPC0gcmVhZEdGRigifi9Eb2N1bWVudHMvSENBL3JlZmVyZW5jZS9nZW5jb2RlLnYyNy5wcmltYXJ5X2Fzc2VtYmx5LmFubm90YXRpb24uZ3RmIiwgdmVyc2lvbj0yTCwgdGFncyA9IGMoImdlbmVfbmFtZSIsImdlbmVfaWQiLCAidHJhbnNjcmlwdF9pZCIsImdlbmVfdHlwZSIpKQpnZW5lczwtc3Vic2V0KGd0Zl9nZW5jb2RlLGd0Zl9nZW5jb2RlJHR5cGUgPT0gImdlbmUiKQptdC5nZW5lczwtc3Vic2V0KGdlbmVzLGdlbmVzJGdlbmVfdHlwZSAlaW4lIGMoJ010X3RSTkEnLCdNdF9yUk5BJykpCmBgYApMb2FkIGRhdGFzZXQuIEFsbCBvdXRwdXRzIG9mIHBpcGVsaW5lLGluY2x1ZGUgbWV0cmljcyBhbmQgcXVhbnRpZmljYXRpb24gaGF2ZSBiZWVuIHNhdmVkIGluIGEgUmRhdGEuCmBgYHtyfQpsb2FkKCdoaXNhdDJfb3V0cHV0c19idW5kbGUuUkRhdGEnKQpgYGAKIyBTZXF1ZW5jaW5nIERhdGEgUUMKR2VuZXJhbCBxdWFsaXR5IGNvbnRyb2wgd2l0aCBzZXF1ZW5jaW5nIGRhdGEKCiMjIEJhc2VjYWxsIFF1YWxpdHkgRGlzdHJpYnV0aW9uClRoZSBtZWFuIHF1YWxpdHkgdmFsdWUgYWNyb3NzIGVhY2ggYmFzZSBwb3NpdGlvbiBpbiB0aGUgcmVhZC4gCmBgYHtyLCBlY2hvID1UUlVFLCBvdXQud2lkdGg9IjMwJSJ9Cm0ucXVhbDwtbWVsdChoaXNhdDIuYmFzZXF1YWxpdHksaWQ9IkJpbiIpCnA8LWdncGxvdChtLnF1YWwsYWVzKHg9QmluLHk9dmFsdWUsZ3JvdXA9dmFyaWFibGUsY29sb3I9dmFsdWUpKStnZW9tX3BvaW50KCkrZ2VvbV9saW5lKCkKcDwtcCsgIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3VycyA9IHJhaW5ib3coMTApKQpwbmdmaWxlPC1wYXN0ZSgnLi9pbWFnZXMvYmFzZV9xdWFsaXR5XzUwYnBfaGlzYXQyLnBuZycsc2VwPScnKQpteWltYWdlczwtcG5nZmlsZQpnZ3NhdmUocGxvdD1wLGZpbGU9cG5nZmlsZSx0eXBlPSdjYWlyby1wbmcnLHdpZHRoPTEwLGhlaWdodD0xMCkKaW5jbHVkZV9ncmFwaGljcyhteWltYWdlcykKYGBgCgoKIyMgQmFzZWNhbGwgRGlzdHJpYnV0aW9uClRoZSBwcm9wb3J0aW9uIG9mIGVhY2ggYmFzZSBwb3NpdGlvbiBmb3Igd2hpY2ggZWFjaCBvZiB0aGUgZm91ciBub3JtYWwgRE5BIGJhc2VzIGFuZCBhIG1pc3NpbmcgYmFzZSBoYXMgYmVlbiBjYWxsZWQuIApgYGB7cixlY2hvID1UUlVFLCBvdXQud2lkdGg9IjMwJSJ9CmNvbG5hbWVzKGhpc2F0Mi5iYXNlY2FsbCkKYjUwPC1uYW1lcyh3aGljaCh0YWJsZShoaXNhdDIuYmFzZWNhbGwkc3JhSUQpPT01MCkpCmRkPC1zdWJzZXQoaGlzYXQyLmJhc2VjYWxsLGhpc2F0Mi5iYXNlY2FsbCRzcmFJRCAlaW4lIGI1MCkKbS5iYzwtbWVsdChkZCxpZD1jKCdzcmFJRCcsJ1JFQURfRU5EJywnQ1lDTEUnKSkKcDwtZ2dwbG90KG0uYmMsYWVzKHg9Q1lDTEUseT12YWx1ZSxncm91cD1pbnRlcmFjdGlvbihzcmFJRCxSRUFEX0VORCksY29sb3I9dmFyaWFibGUpKStnZW9tX2xpbmUoKStmYWNldF9ncmlkKHZhcmlhYmxlfi4pCnBuZ2ZpbGU8LXBhc3RlKCcuL2ltYWdlcy9iYXNlY2FsbF81MGJwX2hpc2F0Mi5wbmcnLHNlcD0nJykKbXlpbWFnZXM8LXBuZ2ZpbGUKZ2dzYXZlKHBsb3Q9cCxmaWxlPXBuZ2ZpbGUsdHlwZT0nY2Fpcm8tcG5nJyx3aWR0aD0xMCxoZWlnaHQ9MTApCmluY2x1ZGVfZ3JhcGhpY3MobXlpbWFnZXMpCmBgYAojIEFsaWdubWVudCBTdGF0aXN0aWNzClR3byBQaWNhcmQgbWV0cmljcyBwcm92aWRlIG1haW4gYWxpZ25tZW50IFFDIG1ldHJpY3MsIGBNYXJrRHVwbGljYXRpb25gIGFuZCBgQ29sbGVjdEFsaWdubWVudE1ldHJpY3NgLgpgYGB7cn0KY29sbmFtZXMoaGlzYXQyLmFsbikKY29sbmFtZXMoaGlzYXQyLmR1cCkKYGBgCiMjIEFsaWdubWVudCBCaWFzIHdpdGhpbiBQYWlycwpDb21wYXJlIGFsaWdubWVudCByYXRlIG9mIGBSMWAgYW5kIGBSMmAKYGBge3IsZWNobyA9VFJVRSwgb3V0LndpZHRoPSIzMCUifQpyMTwtc3Vic2V0KGhpc2F0Mi5hbG4saGlzYXQyLmFsbiRDQVRFR09SWSA9PSAiRklSU1RfT0ZfUEFJUiIpCnIyPC1zdWJzZXQoaGlzYXQyLmFsbixoaXNhdDIuYWxuJENBVEVHT1JZPT0iU0VDT05EX09GX1BBSVIiKQpkZDwtZGF0YS5mcmFtZSgnc3JhSUQnPXIxJHNyYUlELCdSMSc9cjEkUENUX1BGX1JFQURTX0FMSUdORUQsJ1IyJz1yMiRQQ1RfUEZfUkVBRFNfQUxJR05FRCkKbWxpc3Q8LW1hdGNoKGRkJHNyYUlELG1ldGFkYXRhJFJ1bl9zKQptZXRhZGF0YTwtbWV0YWRhdGFbbWxpc3QsXSAjIyBtYXRjaCBtZXRhZGF0IHdpdGggbWV0cmljcyBmaWxlCnA8LWdncGxvdChkZCxhZXMoeD1SMSx5PVIyLGNvbG9yPWFzLmZhY3RvcihtZXRhZGF0YSRBdmdTcG90TGVuX2wpKSkrZ2VvbV9wb2ludCgpCnA8LXArZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsIHNsb3BlPTEsY29sb3I9J2JsdWUnKQpwbmdmaWxlPC1wYXN0ZSgnLi9pbWFnZXMvaGlzYXQyX1IxX1IyX1BDVF9QRl9SRUFEU19BTElHTkVELnBuZycsc2VwPScnKQpnZ3NhdmUocGxvdD1wLGZpbGU9cG5nZmlsZSx0eXBlPSdjYWlyby1wbmcnLHdpZHRoPTEwLGhlaWdodD0xMCkKaW5jbHVkZV9ncmFwaGljcyhwbmdmaWxlKQpgYGAKIyMgQWxpZ25lZCwgbXVsdGlwbGUgYWxpZ25lZCwgdW5tYXBwZWQKQWxpZ25lZCB2cyB1bm1hcHBlZC4gCmBgYHtyfQojI2V4dHJhY3QgbWV0cmljcwp4MTwtc3Vic2V0KGhpc2F0Mi5hbG4saGlzYXQyLmFsbiRDQVRFR09SWSA9PSAiUEFJUiIpCmRkPC1kYXRhLmZyYW1lKCdzcmFJRCc9eDEkc3JhSUQsJ1VOTUFQUEVEJz1oaXNhdDIuZHVwJFVOTUFQUEVEX1JFQURTL3gxJFRPVEFMX1JFQURTLCdNQVBQRUQnPSh4MSRUT1RBTF9SRUFEUy1oaXNhdDIuZHVwJFVOTUFQUEVEX1JFQURTKS94MSRUT1RBTF9SRUFEUykKYWxuLm08LW1lbHQoZGQpCnA8LWdncGxvdChhbG4ubSwgYWVzKHggPSBzcmFJRCx5ID0gdmFsdWUpKSArIGdlb21fYXJlYShhZXMoZmlsbD12YXJpYWJsZSxncm91cCA9IHZhcmlhYmxlKSwgcG9zaXRpb249J3N0YWNrJykKcG5nZmlsZTwtcGFzdGUoJy4vaW1hZ2VzL2hpc2F0Ml9hbG5fbWFwcGVkX3VubWFwcGVkX1BDVF9TdGFja2luZy5wbmcnLHNlcD0nJykKZ2dzYXZlKHBsb3Q9cCxmaWxlPXBuZ2ZpbGUsdHlwZT0nY2Fpcm8tcG5nJyx3aWR0aD0xMCxoZWlnaHQ9MTApCmluY2x1ZGVfZ3JhcGhpY3MocG5nZmlsZSkKYGBgClVuaXF1ZWx5IHZzIG11bHRpcGxlIG1hcHBpbmcgcmVhZHMKYGBge3J9CnVucS5yZHM8LWFzLm51bWVyaWMoaGlzYXQyLmxvZ3NbMywtMV0pKjIrYXMubnVtZXJpYyhoaXNhdDIubG9nc1s4LC0xXSkrYXMubnVtZXJpYyhoaXNhdDIubG9nc1s1LC0xXSkqMgptdWx0LnJkczwtYXMubnVtZXJpYyhoaXNhdDIubG9nc1s0LC0xXSkqMithcy5udW1lcmljKGhpc2F0Mi5sb2dzWzksLTFdKQphbG4ucmRzPC11bnEucmRzK211bHQucmRzCnVucS5wY3Q8LXVucS5yZHMvYWxuLnJkcwptdWx0LnBjdDwtbXVsdC5yZHMvYWxuLnJkcwpkZDwtZGF0YS5mcmFtZSgnc3JhSUQnPWNvbG5hbWVzKGhpc2F0Mi5sb2dzKVstMV0sJ211bHRpLW1hcHBpbmcnPW11bHQucGN0LCd1bmlxLW1hcHBpbmcnPXVucS5wY3QpCm1kZDwtbWVsdChkZCkKcDwtZ2dwbG90KG1kZCwgYWVzKHggPSBzcmFJRCx5ID0gdmFsdWUpKSArIGdlb21fYXJlYShhZXMoZmlsbD12YXJpYWJsZSxncm91cD12YXJpYWJsZSksIHBvc2l0aW9uPSdzdGFjaycpCnBuZ2ZpbGU8LXBhc3RlKCcuL2ltYWdlcy9oaXNhdDJfYWxuX3NlY29uZGFyeV9wcmltYXJ5X1BDVF9TdGFja2luZy5wbmcnLHNlcD0nJykKZ2dzYXZlKHBsb3Q9cCxmaWxlPXBuZ2ZpbGUsdHlwZT0nY2Fpcm8tcG5nJyx3aWR0aD0xMCxoZWlnaHQ9MTApCmluY2x1ZGVfZ3JhcGhpY3MocG5nZmlsZSkKYGBgCiMgUk5BIFFDIG1ldHJpY3MKUk5BIG1ldHJpY3MKYGBge3J9CmNvbG5hbWVzKGhpc2F0Mi5ybmEpCmBgYApXZSByZXBvcnQgYFBDVF9SSUJPU09NQUxfQkFTRVNgLGBQQ1RfQ09ESU5HX0JBU0VTYCxgUENUX1VUUl9CQVNFU2AsYFBDVF9JTlRST05JQ19CQVNFU2AgYW5kIGBQQ1RfSU5URVJHRU5JQ19CQVNFU2AKCmBgYHtyLGVjaG8gPVRSVUUsIG91dC53aWR0aD0iMzAlIn0KIyNleHRyYWN0IG1ldHJpY3MKcm5hPC1oaXNhdDIucm5hWyxjKCdzcmFJRCcsJ1BDVF9JTlRFUkdFTklDX0JBU0VTJywnUENUX0lOVFJPTklDX0JBU0VTJywnUENUX1VUUl9CQVNFUycsJ1BDVF9DT0RJTkdfQkFTRVMnLCdQQ1RfUklCT1NPTUFMX0JBU0VTJyldCnJuYS5tPC1tZWx0KHJuYSkKcDwtZ2dwbG90KHJuYS5tLCBhZXMoeCA9IHNyYUlELHkgPSB2YWx1ZSkpICsgZ2VvbV9hcmVhKGFlcyhmaWxsPXZhcmlhYmxlLGdyb3VwID0gdmFyaWFibGUpLCBwb3NpdGlvbj0nc3RhY2snKQpwbmdmaWxlPC1wYXN0ZSgnLi9pbWFnZXMvaGlzYXQyX1JOQV9QQ1RfU3RhY2tpbmcucG5nJyxzZXA9JycpCmdnc2F2ZShwbG90PXAsZmlsZT1wbmdmaWxlLHR5cGU9J2NhaXJvLXBuZycsd2lkdGg9MTAsaGVpZ2h0PTEwKQppbmNsdWRlX2dyYXBoaWNzKHBuZ2ZpbGUpCmBgYApBbm90aGVyIG1ldHJpY3Mgd2Ugd291bGQgbGlrZSB0byBzaG93IGlzIHRoZSBgQWxsX1JlYWRzLm5vcm1hbGl6ZWRfY292ZXJhZ2VgIGFsb25lIHRyYW5zY3JpcHRzIGFuZCBub3JtYWxpemVkIGJ5IEdDLWNvbnRlbnQuIFBpY2FyZCBmaXJzdCBiaW4gdHJhbnNjcmlwdHMgZnJvbSAzYCB0byA1JyBhbmQgdGhlbiByZXBvcnRzIHRoaXMgbWV0cmljcyBieSBjYWxjdWxhdGluZyByZWFkcyBjb3VudHMgaW4gZWFjaCBiaW4gYWxvbmcgdHJhbnNjcmlwdHMKYGBge3IsZWNobyA9VFJVRSwgb3V0LndpZHRoPSIzMCUifQpjb3YubTwtbWVsdChoaXNhdDIuY292ZXJhZ2UsaWQ9J0JpbicpCm1saXN0PC1tYXRjaChjb3YubSR2YXJpYWJsZSxtZXRhZGF0YSRSdW5fcykKbWRhdGE8LW1ldGFkYXRhJHNvdXJjZV9uYW1lX3NbbWxpc3RdCmNvdi5tPC1kYXRhLmZyYW1lKGNvdi5tLCdjZWxsJz1tZGF0YSkKcDwtZ2dwbG90KGNvdi5tLGFlcyh4PUJpbix5PXZhbHVlLGdyb3VwPWludGVyYWN0aW9uKHZhcmlhYmxlLGNlbGwpLGNvbG9yPWNlbGwpKStnZW9tX2xpbmUoKStmYWNldF9ncmlkKGNlbGx+Likrc2NhbGVfeV9sb2cxMCgpCnBuZ2ZpbGU8LXBhc3RlKCcuL2ltYWdlcy9oaXNhdDJfUk5BX2NvdmVyYWdlLnBuZycsc2VwPScnKQpnZ3NhdmUocGxvdD1wLGZpbGU9cG5nZmlsZSx0eXBlPSdjYWlyby1wbmcnLHdpZHRoPTEwLGhlaWdodD0xMCkKaW5jbHVkZV9ncmFwaGljcyhwbmdmaWxlKQoKYGBgCgojIFF1YW50aWZpY2F0aW9uIFFDCldlIGNhbiBkZWZpbmUgYGRldGVjdGVkIGdlbmVzYCBieSByZXF1aXJlIHRoZSByZWFkcyBjb3VudCBvZiB0aGUgZ2VuZSB0byBiZSBhdCBsZWFzdCBgPjVgCgpgYGB7cn0KIyNkaW0oaGlzYXQycnNlbS5jbnQpCmNudC5kZDwtaGlzYXQycnNlbS5jbnRbLC0xXQojIyB0b3RhbCByZWFkcyBhbG4KY250LnRvdDwtYXBwbHkoY250LmRkLDIsc3VtKQojIyB0b3RhbCBnZW5lIHJlYWRzIGNvdW50CmNudC5nZW5lPC1hcHBseShjbnQuZGQsMixmdW5jdGlvbih4KXtzdW0oeD41KX0pCiMjIG10IGdlbmVzCng8LXN1YnNldChjbnQuZGQsaGlzYXQycnNlbS5jbnQkZW5zSUQgJWluJSBtdC5nZW5lcyRnZW5lX2lkKQojI210IGdlbmUgcmVhZCBjb3VudHMKY250Lm10PC1hcHBseSh4LDIsc3VtKQojIyBjcmVhdGUgZGYKZGQ8LWRhdGEuZnJhbWUoJ3NyYUlEJz1jb2xuYW1lcyhkZCksJ3JlYWRDb3VudHMnPWNudC50b3QsJ210Jz1jbnQubXQsJ2RldGVjdGVkR2VuZXMnPWNudC5nZW5lKQoKYGBgCiMjIFJlYWRzIENvdW50cyBzYXR1cmF0aW9uIHBsb3RzCmBgYHtyfQpwPC1nZ3Bsb3QoZGQsYWVzKHg9cmVhZENvdW50cyx5PWRldGVjdGVkR2VuZXMsY29sb3I9ZGV0ZWN0ZWRHZW5lcykpK2dlb21fcG9pbnQoKStzY2FsZV94X2xvZzEwKCkrc2NhbGVfeV9sb2cxMCgpCnBuZ2ZpbGU8LXBhc3RlKCcuL2ltYWdlcy9oaXNhdDJfZ2VuZV9jb3VudF9zYXR1cmF0aW9uLnBuZycsc2VwPScnKQpnZ3NhdmUocGxvdD1wLGZpbGU9cG5nZmlsZSx0eXBlPSdjYWlyby1wbmcnLHdpZHRoPTEwLGhlaWdodD0xMCkKaW5jbHVkZV9ncmFwaGljcyhwbmdmaWxlKQpgYGAKIyMgbXQgZ2VuZSBjb3ZlcmFnZQoKYGBge3J9CnA8LWdncGxvdChkZCxhZXMoeD1jbnQubXQvcmVhZENvdW50cykpK2dlb21faGlzdG9ncmFtKCkreGxhYignJSBpbiBNVCBnZW5lcycpCnBuZ2ZpbGU8LXBhc3RlKCcuL2ltYWdlcy9oaXNhdDJfbXRfZ2VuZV9jb3VudC5wbmcnLHNlcD0nJykKZ2dzYXZlKHBsb3Q9cCxmaWxlPXBuZ2ZpbGUsdHlwZT0nY2Fpcm8tcG5nJyx3aWR0aD0xMCxoZWlnaHQ9MTApCmluY2x1ZGVfZ3JhcGhpY3MocG5nZmlsZSkKYGBgCg==