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==