Purpose:
Intron Expression in HEK cells
Load the following packages:
library(tidyverse)
library(cowplot)
library(ggsci)
library(ggbeeswarm)
library(ComplexUpset)
library(Gviz)
Load functions:
source("/data/share/htp/prime-seq_Paper/Scripts/custom_functions.R")
theme_pub <- theme_bw() + theme(plot.title = element_text(hjust = 0.5, size=18, face="bold"),
axis.text = element_text(colour="black", size=14),
axis.title=element_text(size=16,face="bold"),
legend.text=element_text(size=14),
legend.position="right",
axis.line.x = element_line(colour = "black"),
axis.line.y = element_line(colour = "black"),
strip.background=element_blank(),
strip.text=element_text(size=16))
theme_set(theme_pub)
fig_path<-here::here()
data_path<-str_split(string = fig_path,pattern = "/analysis",simplify = T)[,1]
## Feature Colours
feat_cols<-c("#F08C4B", "#E5DFCC", "#556f44", "#9dc183", "#4D8C57", "#3A8DB5", "#256EA0","dodgerblue4","#256EA0")
names(feat_cols)<-c("Ambiguity","Intergenic","Ribosomal","Mitochondrial","lncRNA","Intron","Coding","Intragenic","Exon")
inex_colors <- c("#ff5154","#91a6ff","#550527")
names(inex_colors)<-c("Intron","Exon","Both")
Load annotation:
## annotation
gtype_human <-getbiotype("hsapiens_gene_ensembl",species="human")
ensembl <- useMart("ensembl", dataset ="hsapiens_gene_ensembl", host="uswest.ensembl.org")
biotype <- getBM(attributes=c("ensembl_gene_id","ensembl_gene_id_version","gene_biotype","external_gene_name","chromosome_name"),
mart=ensembl )
Load data:
inf <-
read.csv(
paste0(fig_path, "/sample_info.csv"),
header = T,
stringsAsFactors = F
) %>%
mutate(Condition = case_when(
Condition == "Incubation + ProtK" ~ "Magnetic Beads",
TRUE ~ Condition
)) %>%
filter(Celltype == "HEK")
inf$Sample <- as.character(inf$Sample)
counts_hek <-
readRDS(
paste0(
data_path,
"/zUMIs/HEK/zUMIs_output/expression/Bulk_opt_lysis_test_2_HEK.dgecounts.rds"
)
)
# Split into exon, intron and Exon+ intron matrices.
# Filter samples and remove Geneversion numbers
counts_hek_ex <-
counts_hek$umicount$exon$all %>% as.matrix() %>% remove_Geneversion()
counts_hek_ex <- counts_hek_ex[, inf$BC]
counts_hek_inex <-
counts_hek$umicount$inex$all %>% as.matrix() %>% remove_Geneversion()
counts_hek_inex <- counts_hek_inex[, inf$BC]
counts_hek_in <-
counts_hek$umicount$intron$all %>% as.matrix() %>% remove_Geneversion()
counts_hek_in <- counts_hek_in[, inf$BC]
## make exon only / intron only matrix, remove genes detected in both
counts_hek_ex_o <-
counts_hek_ex[!(rownames(counts_hek_ex) %in% rownames(counts_hek_in)), ]
counts_hek_in_o <-
counts_hek_in[!(rownames(counts_hek_in) %in% rownames(counts_hek_ex)), ]
counts_hek_inex_o <-
counts_hek_inex[!(rownames(counts_hek_inex) %in% rownames(counts_hek_ex_o)), ]
counts_hek_inex_o <-
counts_hek_inex_o[!(rownames(counts_hek_inex_o) %in% rownames(counts_hek_in_o)), ]
counts_hek_in_o <- counts_hek_in_o[rowSums(counts_hek_in_o) > 0, ]
counts_hek_ex_o <- counts_hek_ex_o[rowSums(counts_hek_ex_o) > 0, ]
counts_hek_inex_o <- counts_hek_inex_o[rowSums(counts_hek_inex_o) > 0, ]
cond <- c("Magnetic Beads", "Column")
for (i in cond) {
sub_inf <- inf %>%
filter(Condition %in% i)
intron_only_genes <-
rownames(counts_hek_in_o[whichgenes_reproducible(counts_hek_in_o[,sub_inf$BC],
exprcutoff = 5,
reproducecutoff = 0.1), sub_inf$BC])
exon_only_genes <-
rownames(counts_hek_ex_o[whichgenes_reproducible(counts_hek_ex_o[,sub_inf$BC],
exprcutoff = 5,
reproducecutoff = 0.1), sub_inf$BC])
inex_genes <-
rownames(counts_hek_inex_o[whichgenes_reproducible(counts_hek_inex_o[,sub_inf$BC],
exprcutoff = 5,
reproducecutoff = 0.1), sub_inf$BC])
inex_genes <-
inex_genes[order(rowSums(counts_hek_inex_o[whichgenes_reproducible(counts_hek_inex_o[,sub_inf$BC],
exprcutoff = 5,
reproducecutoff = 0.1),
sub_inf$BC]),
decreasing = T)] # sort by highest overall count
gene_type <-
data.frame(
ENSEMBL = c(exon_only_genes, intron_only_genes, inex_genes),
detection = c(
rep("exon", times = length(exon_only_genes)),
rep("intron", times = length(intron_only_genes)),
rep("both", times = length(inex_genes))
)
) %>%
left_join(biotype, by = c("ENSEMBL" = "ensembl_gene_id")) %>%
mutate(
biotype2 = case_when(
grepl(gene_biotype, pattern = "*pseudogene") ~ "pseudogene",
grepl(gene_biotype, pattern = "IG*") ~ "protein coding",
grepl(gene_biotype, pattern = "TR*") ~ "protein coding",
grepl(gene_biotype, pattern = "MT*") ~ "other",
grepl(gene_biotype, pattern = "^s") ~ "small RNA",
grepl(gene_biotype, pattern = "ribozyme") ~ "other",
gene_biotype == "misc_RNA" ~ "other",
gene_biotype == "protein_coding" ~ "protein coding",
T ~ gene_biotype
),
cond = i
) %>%
filter(!(is.na(biotype2)))
gene_type$biotype2 <-
factor(gene_type$biotype2, levels = rev(
c(
"protein coding",
"lncRNA",
"pseudogene",
"rRNA",
"small RNA",
"miRNA",
"not_annotated",
"other"
)
))
if (!(exists("gene_type_sum"))) {
gene_type_sum <- gene_type
} else{
gene_type_sum <- bind_rows(gene_type_sum, gene_type)
}
}
ggplot() +
geom_bar(data = gene_type_sum,
aes(x = cond, fill = biotype2),
#position = position_fill(),
na.rm = T) +
ggsci::scale_fill_npg() +
theme(legend.position = "right") +
labs(fill = "",
x = "",
y = "detected Genes") +
facet_grid(~detection)+
theme(axis.text.x = element_text(angle=45,hjust=1))

NA
NA
No difference in composition based on extraction method. We continue with the Bead isolation Condition from here on.
inf<-inf %>%
filter(Condition=="Magnetic Beads")
gene_type<-gene_type_sum %>%
filter(cond=="Magnetic Beads")
counts_hek_inex<-counts_hek_inex[,inf$BC]
counts_hek_ex_o<-counts_hek_inex[subset(gene_type,detection=="exon")$ENSEMBL,]
counts_hek_in_o<-counts_hek_inex[subset(gene_type,detection=="intron")$ENSEMBL,]
counts_hek_inex_o<-counts_hek_inex[subset(gene_type,!(detection%in%c("intron","exon")))$ENSEMBL,]
##
counts_hek_in <- counts_hek_in[whichgenes_reproducible(counts_hek_in[,inf$BC],
exprcutoff = 2,
reproducecutoff = 0.1), inf$BC]
counts_hek_ex <- counts_hek_ex[whichgenes_reproducible(counts_hek_ex[,inf$BC],
exprcutoff = 2,
reproducecutoff = 0.1), inf$BC]
upset plot of intersections
average_counts<-data.frame(ENSEMBL=rownames(counts_hek_inex),
mean_cnt=rowMeans(counts_hek_inex)
)
intron_genes<-rownames(counts_hek_in) %>%
unique()
exon_genes<-rownames(counts_hek_ex)%>%
unique()
upset_df<-data.frame(ENSEMBL=c(exon_genes,intron_genes),
detection=c(rep("exon",
times=length(exon_genes)),
rep("intron",
times=length(intron_genes))
)) %>%
left_join(biotype,by=c("ENSEMBL"="ensembl_gene_id")) %>%
mutate(biotype2=case_when(grepl(gene_biotype,pattern="*pseudogene")~ "pseudogene",
grepl(gene_biotype,pattern="IG*")~ "protein coding",
grepl(gene_biotype,pattern="TR*")~ "protein coding",
grepl(gene_biotype,pattern="MT*")~ "other",
grepl(gene_biotype,pattern="^s")~ "small RNA",
grepl(gene_biotype,pattern="ribozyme")~ "other",
gene_biotype=="misc_RNA"~ "other",
gene_biotype=="protein_coding"~ "protein coding",
T~gene_biotype)) %>%
filter(!is.na(biotype2)) %>%
inner_join(average_counts)
Joining, by = "ENSEMBL"
upset_df$biotype2<-factor(upset_df$biotype2,levels=rev(c("protein coding","lncRNA","pseudogene","rRNA","small RNA","miRNA","other")))
upset_df<-upset_df %>%
mutate(value=TRUE) %>%
pivot_wider(names_from = detection,values_from = value,values_fill = FALSE) %>%
left_join(gene_type)
Joining, by = c("ENSEMBL", "ensembl_gene_id_version", "gene_biotype", "external_gene_name", "chromosome_name", "biotype2")
categories<-c("exon","intron")
upset<-upset(upset_df,
categories,
name="Gene detection",
base_annotations=list(
'Intersection size'=intersection_size(
counts=FALSE,
mapping=aes(fill=biotype2)
)+scale_fill_npg()
+labs(fill="")
),
annotations = list(
'nUMI'=(
ggplot(mapping=aes(y=mean_cnt,fill=biotype2))
+geom_boxplot(position="dodge",outlier.shape = NA,show.legend = F)
+scale_y_log10()
+scale_fill_npg()
)))
upset
ggsave(upset,
device = "pdf",
path = fig_path,
width = 150,
height=180,
units = "mm",
filename = "upset_plot.pdf"
)

Summary stats
make_summary<-function(mat,type){
data.frame(BC=colnames(mat),
umi=colSums(mat),
gene=colSums(mat>0),
type=type)
}
summary<-rbind(make_summary(counts_hek_ex_o,"Exon"),
make_summary(counts_hek_in_o,"Intron"),
make_summary(counts_hek_inex_o,"Both"))
summary$exclusive<-"yes"
ggplot(summary,aes(y=umi,x=type,col=type))+
geom_boxplot()+
geom_beeswarm()+
scale_y_log10()+
scale_colour_manual(values=inex_colors,limits=force)

ggplot(summary,aes(y=gene,x=type,col=type))+
geom_boxplot()+
geom_beeswarm()+
scale_y_log10()+
scale_colour_manual(values=inex_colors,limits=force)

summary2<-rbind(make_summary(counts_hek_ex,"Exon"),
make_summary(counts_hek_in,"Intron"),
make_summary(counts_hek_inex,"Both"))
summary2$exclusive<-"no"
ggplot(summary2,aes(y=umi,x=type,col=type))+
geom_boxplot()+
geom_beeswarm()+
scale_y_log10()+
ggtitle("")+
scale_colour_manual(values=inex_colors,limits=force)

ggplot(summary2,aes(y=gene,x=type,col=type))+
geom_boxplot()+
geom_beeswarm()+
scale_y_log10()+
scale_colour_manual(values=inex_colors,limits=force)

summary3<-rbind(summary,summary2) #%>%
# pivot_longer(cols=c(umi,gene),names_to = "type2" ,values_to = "count")
ggplot(summary3,aes(type,y=gene,group=paste0(exclusive,type),col=exclusive))+
geom_boxplot()+
geom_beeswarm(dodge.width = 0.80)+
scale_y_log10()

ggplot(summary3,aes(type,y=umi,group=paste0(exclusive,type),col=exclusive))+
geom_boxplot()+
geom_beeswarm(dodge.width = 0.80)+
scale_y_log10()

NA
NA
NA
inex_genes<-rownames(counts_hek_inex)
# subset for genes expressed in both
exon<-counts_hek_ex[rownames(counts_hek_ex)%in%inex_genes,]
exon<-exon[whichgenes_reproducible(exon,5,reproducecutoff = 0.2),]
exon<-exon[,]
intron<-counts_hek_in[rownames(counts_hek_in)%in%inex_genes,]
intron<-intron[whichgenes_reproducible(intron,5,reproducecutoff = 0.2),]
inex_lib<-data.frame(sample=names(colSums(counts_hek_inex)),
LibSize=colSums(counts_hek_inex))
## normalize to UMI per million
upm<-function(umi_counts){
umi_counts%>%
as.data.frame() %>%
rownames_to_column(var="GeneID") %>%
pivot_longer( cols = 2:ncol(.),
names_to = "sample",
values_to = "cnt") %>%
left_join(inex_lib) %>%
group_by(sample) %>%
mutate(upm = cnt / LibSize *1e6 ) %>%
dplyr::select(-c(LibSize,cnt))%>%
pivot_wider(names_from = sample,
values_from = upm) %>%
column_to_rownames(var = "GeneID") %>%
as.matrix()
}
exon_upm<-upm(exon)
Joining, by = "sample"
exon_upm<-log2(exon_upm+1)
head(exon_upm)
AAAACT ATATAG GTTTAT TGTTTA GCTAGA CCCACG CGGTGG GCTCGC AAAGTT ATCAAA TAAAGT TTAATC
ENSG00000000003 6.777043 6.894788 6.881346 6.944080 6.935219 7.1598135 6.991783 7.197138 6.375255 6.389947 6.430394 6.690962
ENSG00000000419 5.572084 5.541948 5.722610 5.331175 4.769669 5.2074211 5.363794 5.931007 4.515383 4.605971 4.806156 4.524692
ENSG00000000457 2.626398 1.880397 3.364346 2.689834 2.859309 1.8860013 2.270964 3.792812 2.097778 1.704817 2.677023 3.132752
ENSG00000000460 3.928917 4.865845 4.638661 4.511567 4.896307 4.2459487 4.331438 4.886397 3.285104 3.706273 3.267919 3.802377
ENSG00000000971 0.000000 0.000000 0.000000 0.000000 0.000000 0.9250104 1.542618 0.000000 1.065916 0.000000 1.055938 1.198606
ENSG00000001036 6.173004 6.197858 6.236245 6.332796 6.385227 6.2907196 5.914327 6.120693 5.680913 5.598644 5.599290 5.722660
GGGATT CCCCGT CGTGGG GGAGCC
ENSG00000000003 6.469344 6.334377 6.876656 6.983402
ENSG00000000419 4.328676 4.681841 4.684511 4.822240
ENSG00000000457 1.086215 1.943430 2.179717 3.335826
ENSG00000000460 3.147655 3.928934 4.026753 3.959295
ENSG00000000971 0.000000 0.000000 0.000000 0.000000
ENSG00000001036 5.836887 5.879522 6.340348 5.888000
intron_upm<-upm(intron)
Joining, by = "sample"
intron_upm<-log2(intron_upm+1)
head(intron_upm)
AAAACT ATATAG GTTTAT TGTTTA GCTAGA CCCACG CGGTGG GCTCGC AAAGTT ATCAAA TAAAGT TTAATC
ENSG00000000003 0.000000 1.227052 1.870535 0.000000 1.170781 0.9250104 0.000000 0.000000 2.425995 0.810066 1.659075 1.198606
ENSG00000000419 2.900825 3.707959 3.695444 4.023849 3.088823 3.9429054 3.641473 3.258980 2.693206 2.649165 2.677023 3.802377
ENSG00000000457 2.900825 0.000000 1.870535 2.422748 2.586247 2.4577228 2.752681 2.747467 1.672198 2.464603 3.096513 0.000000
ENSG00000000460 4.256398 4.651676 4.475957 4.205365 4.393785 4.8509811 4.582480 4.181589 4.444698 3.936642 3.685914 4.603667
ENSG00000001036 1.842944 0.000000 0.000000 1.063833 1.170781 0.0000000 0.000000 1.280269 1.065916 0.810066 1.055938 1.198606
ENSG00000001084 4.350893 4.095129 4.475957 4.820789 4.393785 4.8053408 4.892314 3.635841 3.577125 3.529332 4.426421 4.048073
GGGATT CCCCGT CGTGGG GGAGCC
ENSG00000000003 0.000000 0.962534 1.122263 0.000000
ENSG00000000419 3.473587 4.016111 3.674553 2.691105
ENSG00000000457 2.127464 2.521967 2.783333 2.213726
ENSG00000000460 4.481563 3.836148 4.026753 4.393207
ENSG00000001036 2.127464 0.000000 0.000000 1.495367
ENSG00000001084 4.481563 3.736982 4.309621 3.574847
df<-data.frame(ENSEMBL=rownames(exon_upm),exon=rowMeans(exon_upm)) %>%
inner_join(data.frame(ENSEMBL=rownames(intron_upm),intron=rowMeans(intron_upm))) %>%
inner_join(gene_type) %>%
filter(biotype2%in%c("protein coding")) %>%
unique()
Joining, by = "ENSEMBL"
Joining, by = "ENSEMBL"
smc_inex<-ggplot(df) + aes(x=exon, y=intron)+
stat_density2d(geom="tile", aes(fill=..density..^0.25, alpha=1), contour=FALSE,show.legend = F) +
geom_point(size=0.5,show.legend = F) +
stat_density2d(geom="tile", aes(fill=..density..^0.25, alpha=ifelse(..density..^0.25<0.15,0,1)), contour=FALSE,show.legend = F) +
scale_fill_gradientn(colours = colorRampPalette(c("white", blues9,"black"))(256))+
theme(panel.grid = element_blank())+
geom_smooth(aes(exon,intron),method="lm",col="grey70")+
labs(x="Log Mean expression Exon",y="Log Mean expression Intron")
smc_inex
`geom_smooth()` using formula 'y ~ x'

hist.inex<-df %>%
rename(Exon=exon,
Intron=intron) %>%
pivot_longer(cols = c("Exon","Intron")) %>%
ggplot()+
geom_histogram(aes(value,fill=name),alpha=0.8,colour="grey50",bins = 50)+
scale_fill_manual(values = inex_colors,limits=force)+
labs(x="Log Mean Expression",
fill="")+
theme(legend.position = c(0.8,0.5),
legend.background = element_blank())
hist.inex
ggsave(smc_inex,
device = "pdf",
path = fig_path,
width = 100,
height=100,
units = "mm",
filename = "scatter_plot.pdf"
)
`geom_smooth()` using formula 'y ~ x'
ggsave(hist.inex,
device = "pdf",
path = fig_path,
width = 100,
height=100,
units = "mm",
filename = "exp_dist_plot.pdf"
)

ranked exon vs. intron expression
rank_mat<-function(count_mat){
count_mat%>%
as.data.frame() %>%
rownames_to_column(var="GeneID") %>%
pivot_longer( cols = 2:ncol(.),
names_to = "sample",
values_to = "cnt") %>%
arrange(GeneID,cnt) %>%
group_by(sample) %>%
mutate(gene_rank = rank(cnt)) %>%
dplyr::select(-cnt) %>%
pivot_wider(names_from = sample,
values_from = gene_rank) %>%
ungroup() %>%
column_to_rownames(var = "GeneID") %>%
as.matrix()
}
exon_rank<-rank_mat(exon)
intron_rank<-rank_mat(intron)
df_rank<-data.frame(ENSEMBL=rownames(exon_rank),
exon_rank=rowMeans(exon_rank)) %>%
inner_join(data.frame(ENSEMBL=rownames(intron_rank),
intron_rank=rowMeans(intron_rank))) %>%
inner_join(df) %>%
filter(biotype2%in%c("protein coding","lncRNA")) %>%
mutate(norm_rank_exon=exon_rank/max(exon_rank),
norm_rank_intron=intron_rank/max(intron_rank))
Joining, by = "ENSEMBL"
Joining, by = "ENSEMBL"
ggplot(df_rank)+
geom_density2d_filled(aes(exon_rank,intron_rank),)+
geom_smooth(aes(exon_rank,intron_rank),method="lm")+
facet_wrap(~biotype2,nrow=2,scales="free")
`geom_smooth()` using formula 'y ~ x'

ggplot(df_rank)+
ggpointdensity::geom_pointdensity(aes(norm_rank_exon,norm_rank_intron),size=0.2)+
geom_smooth(aes(norm_rank_exon,norm_rank_intron),method="lm")+
facet_wrap(~biotype2,nrow=2,scales="free")
`geom_smooth()` using formula 'y ~ x'

NA
Intron vs. Exon mapping
1: subset .bam file for barcodes 2: run get3distance_v3_SP_v2.R for intron and for exon separately 3: combine outputs and plot
bam_path<- "/data/share/htp/prime-seq_Paper/Fig_beads_columns/zUMIs/HEK/zUMIs_output/demultiplexed/"
bam_files<-list.files(path = bam_path,pattern = ".bam$")
bcs<-inf$XC
bam_files<-bam_files[str_split(bam_files,pattern = "[.]",simplify = T)[,2] %in% bcs]
get per bam file geneBody coverage
# library(GenomicRanges, quietly=T, warn.conflicts = F)
# library(GenomicFeatures, quietly=T, warn.conflicts = F)
# library(GenomicAlignments, quietly=T, warn.conflicts = F)
#
# ## Inputs:
# #bam_files #with corresponding .bai
# #out #"name base for plot and outtable"
# counts_hek_inex<-counts_hek$umicount$inex$all %>% as.matrix()
# counts_hek_inex<-counts_hek_inex[,inf$BC]
#
# inex_genes<-rownames(counts_hek_inex)
#
# inex_genes<-inex_genes[order(rowSums(counts_hek_inex),decreasing = T)] # sort by highest overall count
#
# genes <- inex_genes[1:2000] #if you want to subset genes, list of ENSG ids
# write.table(genes,paste0(bam_path,"inex.genes.txt"),quote = F,row.names = F,col.names = F)
# genes<-paste0(bam_path,"inex.genes.txt")
#
# #ftype" #"intron or exon"
#
# gtf<- "/data/share/htp/prime-seq_Paper/genomes/Hsap/gencode.v35.primary_assembly.annotation.gtf" #gtf file containing the transcript info"
# txdb <- makeTxDbFromGFF(gtf, format="gtf")
#
# # restrict to canonical chromosomes
#
# canonical_chr<-seqlevels(txdb)[1:25]
#
#
# tmp<-transcriptsBy(txdb, by="gene")
# gene2transcript<-lapply( tmp, function(x){ mcols(x)$tx_name })
#
# saveDb(txdb, file="/data/share/htp/prime-seq_Paper/genomes/Hsap/gencode.v35.primary_assembly.sqlite")
# save(gene2transcript,file="/data/share/htp/prime-seq_Paper/genomes/Hsap/gene2transcript_canonical.Rdata" )
#
# txdb<-"/data/share/htp/prime-seq_Paper/genomes/Hsap/gencode.v35.primary_assembly.sqlite"
# g2t<-"/data/share/htp/prime-seq_Paper/genomes/Hsap/gene2transcript_canonical.Rdata"
#
# maxTdist <- 10000 #"max dist. to 3' end counted"
# minTlength <- 0 #"minimal length of transcripts considered"
# max_exon_length<- 5000 # max length of exons per gene
# ngenes<- 2000 #max number of genes to use
#
# # i="HEK.ACTGAGCGAAAACT.demx.bam"
# # j="intron"
#
# # index
# for (i in bam_files){
# if (!(file.exists(paste0(bam_path,i,".bai"))))
#
# # index bam file
# system(paste0("samtools index ",bam_path,i))
#
# }
#
#
# ## start slurm jobs
# for (i in bam_files){
# for (j in c("exon","intron")){
# out<- str_split(i,pattern = "[.]",simplify = T)[,2]
#
#
# system(
# paste0(
# "sbatch -J ",
# out,
# " --wrap '/opt/bin/Rscript",
# " /data/share/common/scripts/get3distance_v3_SP_v2_LW_v1.R",
# " --bamfile ",
# paste0(bam_path, i),
# " --txdb ",
# txdb,
# " --g2tmapping ",
# g2t,
# " --out ",
# paste0(out,"_", j),
# " --minTlength ",
# minTlength,
# " --max_exon_length ",
# max_exon_length,
# " --ftype ",
# j,
# " --plot F ",
# " --canonical T ",
# " --genes ",
# genes,
# " --ngenes ",
# ngenes,
# "'"
# )
# )
#
# }}
#
same for intron only genes
## start slurm jobs
for (i in bam_files){
out<- str_split(i,pattern = "[.]",simplify = T)[,2]
system(
paste0(
"sbatch -J ",
out,
" --wrap '/opt/bin/Rscript",
" /data/share/common/scripts/get3distance_v3_SP_v2_LW_v1.R",
" --bamfile ",
paste0(bam_path, i),
" --txdb ",
txdb,
" --g2tmapping ",
g2t,
" --out ",
paste0(out,"_", "intron_only"),
" --minTlength ",
minTlength,
" --max_exon_length ",
max_exon_length,
" --ftype ",
"intron",
" --plot F ",
" --canonical T ",
" --genes ",
genes,
" --ngenes ",
ngenes,
"'"
)
)
}
Submitted batch job 203096
Submitted batch job 203097
Submitted batch job 203098
Submitted batch job 203099
Submitted batch job 203100
Submitted batch job 203101
Submitted batch job 203102
Submitted batch job 203103
Submitted batch job 203104
Submitted batch job 203105
Submitted batch job 203106
Submitted batch job 203107
Submitted batch job 203108
Submitted batch job 203109
Submitted batch job 203110
Submitted batch job 203111
ggsave(p_enrich,
device = "pdf",
path = fig_path,
width = 180,
height=100,
units = "mm",
filename = "enrich_plot.pdf"
)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
check bam coverage for genes with high intron and exon expression
top_genes_inex<-df_rank %>%
filter(!(is.na(external_gene_name))) %>%
filter(!(is.na(chromosome_name))) %>%
filter(exon_rank<19500 & intron_rank> 15500) %>%
arrange(desc(exon_rank)) %>%
unique() %>%
slice_max(exon_rank,n=20)
colnames(exon)<-paste0(colnames(exon),"_Exon")
colnames(intron)<-paste0(colnames(intron),"_Intron")
full_mat<-list(rownames_to_column(as.data.frame(exon),var="Gene_ID"),rownames_to_column(as.data.frame(intron),var="Gene_ID")) %>%
plyr::join_all() %>%
column_to_rownames(var="Gene_ID") %>%
as.data.frame() %>%
as.matrix()
Joining by: Gene_ID
full_mat[is.na(full_mat)]<-0
inex_mat<-full_mat[,17:32]+full_mat[,1:16]
colnames(inex_mat)<-paste0(str_split(colnames(inex_mat),pattern = "_",simplify = T)[,1],"_Both")
full_mat <-list(rownames_to_column(as.data.frame(inex_mat),var="Gene_ID"),rownames_to_column(as.data.frame(full_mat),var="Gene_ID")) %>%
plyr::join_all() %>%
column_to_rownames(var="Gene_ID") %>%
as.data.frame() %>%
as.matrix()
Joining by: Gene_ID
top_genes_mat<-full_mat[top_genes_inex$ENSEMBL,] %>%
t() %>%
as.data.frame() %>%
rownames_to_column(var="Sample") %>%
mutate(type=str_split(Sample,pattern = "_",simplify = T)[,2])
top_genes_mat%>%
dplyr::select(c(type,top_genes_inex$ENSEMBL[1])) %>%
rename("Ensembl"=top_genes_inex$ENSEMBL[1]) %>%
ggplot(aes(y=Ensembl,x=type,fill=type))+
geom_boxplot()+
coord_flip()+
facet_grid(type~.,scale="free")+
theme(axis.text.y = element_blank(),
axis.ticks.y= element_blank())+
labs(x="",y=paste0("UMIs (",top_genes_inex$external_gene_name[1],")"))+
scale_fill_manual(values=inex_colors)

top_genes_mat$type<-factor(top_genes_mat$type,levels=rev(c("Intron","Exon","Both")))
plot coverage for most highly expressed exons and introns

Export plot for ENAH
Plot_Coverage(PRange=PRange,
annot.colors=annot.colors,
b.inf=b.inf,
gene.models=gene.models,
figure.name=figure.name1,
gen=gen,
type=type,
pdf=T,
title=top_genes_inex$external_gene_name[i],
extend.range=2e4,
ymax=400
)
null device
1
intron_only_geneinfo<-upset_df[which(upset_df$ENSEMBL%in%intron_only_genes),] %>%
filter(!duplicated(ENSEMBL)) %>%
column_to_rownames(var = "ENSEMBL")
for (i in intron_only_genes[1:20]){
PRange <- gtf %>%
as.tibble %>%
mutate(ENSG=str_split_fixed(gene_id,
pattern = "[.]",
n = 2)[, 1]) %>%
filter(ENSG %in% i) %>%
group_by(seqnames, strand, gene_id) %>%
summarize(start = min(start), end = max(end)) %>%
plyranges::as_granges()
print(width(PRange))
figure.name1 = paste0("coveragePlots/Intron_only_mapping_",i,".pdf")
Plot_Coverage(PRange=PRange,
annot.colors=annot.colors,
b.inf=b.inf,
gene.models=gene.models,
figure.name=figure.name1,
gen=gen,
type=type,
pdf=T,
title=intron_only_geneinfo[i,"external_gene_name"],
extend.range=width(PRange)*0.5,
ymax=800
)
}
LS0tCnRpdGxlOiAiSW50cm9uIEV4cHJlc3Npb24gLSBIRUsiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyMgUHVycG9zZTogCkludHJvbiBFeHByZXNzaW9uIGluIEhFSyBjZWxscwoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCmBgYAoKCiMjIyAgTG9hZCB0aGUgZm9sbG93aW5nIHBhY2thZ2VzOgoKYGBge3IgcGFja2FnZXN9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkoZ2diZWVzd2FybSkKbGlicmFyeShDb21wbGV4VXBzZXQpCmxpYnJhcnkoR3ZpeikKCmBgYAoKIyMjICBMb2FkIGZ1bmN0aW9uczoKCmBgYHtyfQpzb3VyY2UoIi9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvU2NyaXB0cy9jdXN0b21fZnVuY3Rpb25zLlIiKQoKdGhlbWVfcHViIDwtIHRoZW1lX2J3KCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplPTE4LCBmYWNlPSJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIsIHNpemU9MTQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYsZmFjZT0iYm9sZCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2KSkgIAoKdGhlbWVfc2V0KHRoZW1lX3B1YikKCgpmaWdfcGF0aDwtaGVyZTo6aGVyZSgpCmRhdGFfcGF0aDwtc3RyX3NwbGl0KHN0cmluZyA9IGZpZ19wYXRoLHBhdHRlcm4gPSAiL2FuYWx5c2lzIixzaW1wbGlmeSA9IFQpWywxXQojIyBGZWF0dXJlIENvbG91cnMKCmZlYXRfY29sczwtYygiI0YwOEM0QiIsICIjRTVERkNDIiwgIiM1NTZmNDQiLCAiIzlkYzE4MyIsICIjNEQ4QzU3IiwgIiMzQThEQjUiLCAiIzI1NkVBMCIsImRvZGdlcmJsdWU0IiwiIzI1NkVBMCIpCgpuYW1lcyhmZWF0X2NvbHMpPC1jKCJBbWJpZ3VpdHkiLCJJbnRlcmdlbmljIiwiUmlib3NvbWFsIiwiTWl0b2Nob25kcmlhbCIsImxuY1JOQSIsIkludHJvbiIsIkNvZGluZyIsIkludHJhZ2VuaWMiLCJFeG9uIikKCmluZXhfY29sb3JzIDwtIGMoIiNmZjUxNTQiLCIjOTFhNmZmIiwiIzU1MDUyNyIsIiNCQzcyMzgiKQpuYW1lcyhpbmV4X2NvbG9ycyk8LWMoIkludHJvbiIsIkV4b24iLCJCb3RoIiwiSW50cm9uIG9ubHkiKQoKYGBgCgojIyMgIExvYWQgYW5ub3RhdGlvbjoKCmBgYHtyfQojIyBhbm5vdGF0aW9uCmd0eXBlX2h1bWFuIDwtZ2V0YmlvdHlwZSgiaHNhcGllbnNfZ2VuZV9lbnNlbWJsIixzcGVjaWVzPSJodW1hbiIpCgplbnNlbWJsIDwtIHVzZU1hcnQoImVuc2VtYmwiLCBkYXRhc2V0ID0iaHNhcGllbnNfZ2VuZV9lbnNlbWJsIiwgaG9zdD0idXN3ZXN0LmVuc2VtYmwub3JnIikgCgpiaW90eXBlIDwtIGdldEJNKGF0dHJpYnV0ZXM9YygiZW5zZW1ibF9nZW5lX2lkIiwiZW5zZW1ibF9nZW5lX2lkX3ZlcnNpb24iLCJnZW5lX2Jpb3R5cGUiLCJleHRlcm5hbF9nZW5lX25hbWUiLCJjaHJvbW9zb21lX25hbWUiKSwKICAgICAgICAgICAgICAgICBtYXJ0PWVuc2VtYmwgKQoKYGBgCgojIyMgIExvYWQgZGF0YToKCmBgYHtyfQoKaW5mIDwtCiAgcmVhZC5jc3YoCiAgICBwYXN0ZTAoZmlnX3BhdGgsICIvc2FtcGxlX2luZm8uY3N2IiksCiAgICBoZWFkZXIgPSBULAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYKICApICU+JQogIG11dGF0ZShDb25kaXRpb24gPSBjYXNlX3doZW4oCiAgICBDb25kaXRpb24gPT0gIkluY3ViYXRpb24gKyBQcm90SyIgfiAiTWFnbmV0aWMgQmVhZHMiLAogICAgVFJVRSB+IENvbmRpdGlvbgogICkpICU+JQogIGZpbHRlcihDZWxsdHlwZSA9PSAiSEVLIikKCmluZiRTYW1wbGUgPC0gYXMuY2hhcmFjdGVyKGluZiRTYW1wbGUpCgoKY291bnRzX2hlayA8LQogIHJlYWRSRFMoCiAgICBwYXN0ZTAoCiAgICAgIGRhdGFfcGF0aCwKICAgICAgIi96VU1Jcy9IRUsvelVNSXNfb3V0cHV0L2V4cHJlc3Npb24vQnVsa19vcHRfbHlzaXNfdGVzdF8yX0hFSy5kZ2Vjb3VudHMucmRzIgogICAgKQogICkKCiMgU3BsaXQgaW50byBleG9uLCBpbnRyb24gYW5kIEV4b24rIGludHJvbiBtYXRyaWNlcy4KIyBGaWx0ZXIgc2FtcGxlcyBhbmQgcmVtb3ZlIEdlbmV2ZXJzaW9uIG51bWJlcnMKCmNvdW50c19oZWtfZXggPC0KICBjb3VudHNfaGVrJHVtaWNvdW50JGV4b24kYWxsICU+JSBhcy5tYXRyaXgoKSAlPiUgcmVtb3ZlX0dlbmV2ZXJzaW9uKCkKY291bnRzX2hla19leCA8LSBjb3VudHNfaGVrX2V4WywgaW5mJEJDXQpjb3VudHNfaGVrX2luZXggPC0KICBjb3VudHNfaGVrJHVtaWNvdW50JGluZXgkYWxsICU+JSBhcy5tYXRyaXgoKSAlPiUgcmVtb3ZlX0dlbmV2ZXJzaW9uKCkKY291bnRzX2hla19pbmV4IDwtIGNvdW50c19oZWtfaW5leFssIGluZiRCQ10KY291bnRzX2hla19pbiA8LQogIGNvdW50c19oZWskdW1pY291bnQkaW50cm9uJGFsbCAgJT4lIGFzLm1hdHJpeCgpICU+JSByZW1vdmVfR2VuZXZlcnNpb24oKQpjb3VudHNfaGVrX2luIDwtIGNvdW50c19oZWtfaW5bLCBpbmYkQkNdCgojIyBtYWtlIGV4b24gb25seSAvIGludHJvbiBvbmx5IG1hdHJpeCwgcmVtb3ZlIGdlbmVzIGRldGVjdGVkIGluIGJvdGgKY291bnRzX2hla19leF9vIDwtCiAgY291bnRzX2hla19leFshKHJvd25hbWVzKGNvdW50c19oZWtfZXgpICVpbiUgcm93bmFtZXMoY291bnRzX2hla19pbikpLCBdCmNvdW50c19oZWtfaW5fbyA8LQogIGNvdW50c19oZWtfaW5bIShyb3duYW1lcyhjb3VudHNfaGVrX2luKSAlaW4lIHJvd25hbWVzKGNvdW50c19oZWtfZXgpKSwgXQpjb3VudHNfaGVrX2luZXhfbyA8LQogIGNvdW50c19oZWtfaW5leFshKHJvd25hbWVzKGNvdW50c19oZWtfaW5leCkgJWluJSByb3duYW1lcyhjb3VudHNfaGVrX2V4X28pKSwgXQpjb3VudHNfaGVrX2luZXhfbyA8LQogIGNvdW50c19oZWtfaW5leF9vWyEocm93bmFtZXMoY291bnRzX2hla19pbmV4X28pICVpbiUgcm93bmFtZXMoY291bnRzX2hla19pbl9vKSksIF0KCmNvdW50c19oZWtfaW5fbyA8LSBjb3VudHNfaGVrX2luX29bcm93U3Vtcyhjb3VudHNfaGVrX2luX28pID4gMCwgXQpjb3VudHNfaGVrX2V4X28gPC0gY291bnRzX2hla19leF9vW3Jvd1N1bXMoY291bnRzX2hla19leF9vKSA+IDAsIF0KY291bnRzX2hla19pbmV4X28gPC0gY291bnRzX2hla19pbmV4X29bcm93U3Vtcyhjb3VudHNfaGVrX2luZXhfbykgPiAwLCBdCgpjb25kIDwtIGMoIk1hZ25ldGljIEJlYWRzIiwgIkNvbHVtbiIpCgoKZm9yIChpIGluIGNvbmQpIHsKICAKICBzdWJfaW5mIDwtIGluZiAlPiUKICAgIGZpbHRlcihDb25kaXRpb24gJWluJSBpKQogIAogIGludHJvbl9vbmx5X2dlbmVzIDwtCiAgICByb3duYW1lcyhjb3VudHNfaGVrX2luX29bd2hpY2hnZW5lc19yZXByb2R1Y2libGUoY291bnRzX2hla19pbl9vWyxzdWJfaW5mJEJDXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByY3V0b2ZmID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXByb2R1Y2VjdXRvZmYgPSAwLjEpLCBzdWJfaW5mJEJDXSkKICAKICBleG9uX29ubHlfZ2VuZXMgPC0KICAgIHJvd25hbWVzKGNvdW50c19oZWtfZXhfb1t3aGljaGdlbmVzX3JlcHJvZHVjaWJsZShjb3VudHNfaGVrX2V4X29bLHN1Yl9pbmYkQkNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJjdXRvZmYgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcHJvZHVjZWN1dG9mZiA9IDAuMSksIHN1Yl9pbmYkQkNdKQogIAogIGluZXhfZ2VuZXMgPC0KICAgIHJvd25hbWVzKGNvdW50c19oZWtfaW5leF9vW3doaWNoZ2VuZXNfcmVwcm9kdWNpYmxlKGNvdW50c19oZWtfaW5leF9vWyxzdWJfaW5mJEJDXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJjdXRvZmYgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwcm9kdWNlY3V0b2ZmID0gMC4xKSwgc3ViX2luZiRCQ10pCiAgCiAgaW5leF9nZW5lcyA8LQogICAgaW5leF9nZW5lc1tvcmRlcihyb3dTdW1zKGNvdW50c19oZWtfaW5leF9vW3doaWNoZ2VuZXNfcmVwcm9kdWNpYmxlKGNvdW50c19oZWtfaW5leF9vWyxzdWJfaW5mJEJDXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByY3V0b2ZmID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXByb2R1Y2VjdXRvZmYgPSAwLjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9pbmYkQkNdKSwKICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFQpXSAjIHNvcnQgYnkgaGlnaGVzdCBvdmVyYWxsIGNvdW50CiAgCiAgZ2VuZV90eXBlIDwtCiAgICBkYXRhLmZyYW1lKAogICAgICBFTlNFTUJMID0gYyhleG9uX29ubHlfZ2VuZXMsIGludHJvbl9vbmx5X2dlbmVzLCBpbmV4X2dlbmVzKSwKICAgICAgZGV0ZWN0aW9uID0gYygKICAgICAgICByZXAoImV4b24iLCB0aW1lcyA9IGxlbmd0aChleG9uX29ubHlfZ2VuZXMpKSwKICAgICAgICByZXAoImludHJvbiIsIHRpbWVzID0gbGVuZ3RoKGludHJvbl9vbmx5X2dlbmVzKSksCiAgICAgICAgcmVwKCJib3RoIiwgdGltZXMgPSBsZW5ndGgoaW5leF9nZW5lcykpCiAgICAgICkKICAgICkgJT4lCiAgICBsZWZ0X2pvaW4oYmlvdHlwZSwgYnkgPSBjKCJFTlNFTUJMIiA9ICJlbnNlbWJsX2dlbmVfaWQiKSkgJT4lCiAgICBtdXRhdGUoCiAgICAgIGJpb3R5cGUyID0gY2FzZV93aGVuKAogICAgICAgIGdyZXBsKGdlbmVfYmlvdHlwZSwgcGF0dGVybiA9ICIqcHNldWRvZ2VuZSIpIH4gInBzZXVkb2dlbmUiLAogICAgICAgIGdyZXBsKGdlbmVfYmlvdHlwZSwgcGF0dGVybiA9ICJJRyoiKSB+ICJwcm90ZWluIGNvZGluZyIsCiAgICAgICAgZ3JlcGwoZ2VuZV9iaW90eXBlLCBwYXR0ZXJuID0gIlRSKiIpIH4gInByb3RlaW4gY29kaW5nIiwKICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUsIHBhdHRlcm4gPSAiTVQqIikgfiAib3RoZXIiLAogICAgICAgIGdyZXBsKGdlbmVfYmlvdHlwZSwgcGF0dGVybiA9ICJecyIpIH4gInNtYWxsIFJOQSIsCiAgICAgICAgZ3JlcGwoZ2VuZV9iaW90eXBlLCBwYXR0ZXJuID0gInJpYm96eW1lIikgfiAib3RoZXIiLAogICAgICAgIGdlbmVfYmlvdHlwZSA9PSAibWlzY19STkEiIH4gIm90aGVyIiwKICAgICAgICBnZW5lX2Jpb3R5cGUgPT0gInByb3RlaW5fY29kaW5nIiB+ICJwcm90ZWluIGNvZGluZyIsCiAgICAgICAgVCB+IGdlbmVfYmlvdHlwZQogICAgICApLAogICAgICBjb25kID0gaQogICAgKSAlPiUKICAgIGZpbHRlcighKGlzLm5hKGJpb3R5cGUyKSkpCiAgCiAgZ2VuZV90eXBlJGJpb3R5cGUyIDwtCiAgICBmYWN0b3IoZ2VuZV90eXBlJGJpb3R5cGUyLCBsZXZlbHMgPSByZXYoCiAgICAgIGMoCiAgICAgICAgInByb3RlaW4gY29kaW5nIiwKICAgICAgICAibG5jUk5BIiwKICAgICAgICAicHNldWRvZ2VuZSIsCiAgICAgICAgInJSTkEiLAogICAgICAgICJzbWFsbCBSTkEiLAogICAgICAgICJtaVJOQSIsCiAgICAgICAgIm5vdF9hbm5vdGF0ZWQiLAogICAgICAgICJvdGhlciIKICAgICAgKQogICAgKSkKICAKICBpZiAoIShleGlzdHMoImdlbmVfdHlwZV9zdW0iKSkpIHsKICAgIGdlbmVfdHlwZV9zdW0gPC0gZ2VuZV90eXBlCiAgICAKICB9IGVsc2V7CiAgICBnZW5lX3R5cGVfc3VtIDwtIGJpbmRfcm93cyhnZW5lX3R5cGVfc3VtLCBnZW5lX3R5cGUpCiAgfQogIAp9CgpnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoZGF0YSA9IGdlbmVfdHlwZV9zdW0sCiAgICAgICAgICAgYWVzKHggPSBjb25kLCBmaWxsID0gYmlvdHlwZTIpLAogICAgICAgICAgICNwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwoKSwKICAgICAgICAgICBuYS5ybSA9IFQpICsKICBnZ3NjaTo6c2NhbGVfZmlsbF9ucGcoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIGxhYnMoZmlsbCA9ICIiLAogICAgICAgeCA9ICIiLAogICAgICAgeSA9ICJkZXRlY3RlZCBHZW5lcyIpICsKICBmYWNldF9ncmlkKH5kZXRlY3Rpb24pKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpKQoKCmBgYAoKTm8gZGlmZmVyZW5jZSBpbiBjb21wb3NpdGlvbiBiYXNlZCBvbiBleHRyYWN0aW9uIG1ldGhvZC4gV2UgY29udGludWUgd2l0aCB0aGUgQmVhZCBpc29sYXRpb24gQ29uZGl0aW9uIGZyb20gaGVyZSBvbi4KCmBgYHtyIGZpbHRlciBmb3IgYmVhZHMgb25seX0KCmluZjwtaW5mICU+JSAKICBmaWx0ZXIoQ29uZGl0aW9uPT0iTWFnbmV0aWMgQmVhZHMiKQoKZ2VuZV90eXBlPC1nZW5lX3R5cGVfc3VtICU+JSAKICBmaWx0ZXIoY29uZD09Ik1hZ25ldGljIEJlYWRzIikKCmNvdW50c19oZWtfaW5leDwtY291bnRzX2hla19pbmV4WyxpbmYkQkNdCgpjb3VudHNfaGVrX2V4X288LWNvdW50c19oZWtfaW5leFtzdWJzZXQoZ2VuZV90eXBlLGRldGVjdGlvbj09ImV4b24iKSRFTlNFTUJMLF0KCmNvdW50c19oZWtfaW5fbzwtY291bnRzX2hla19pbmV4W3N1YnNldChnZW5lX3R5cGUsZGV0ZWN0aW9uPT0iaW50cm9uIikkRU5TRU1CTCxdCgpjb3VudHNfaGVrX2luZXhfbzwtY291bnRzX2hla19pbmV4W3N1YnNldChnZW5lX3R5cGUsIShkZXRlY3Rpb24laW4lYygiaW50cm9uIiwiZXhvbiIpKSkkRU5TRU1CTCxdCgojIwoKY291bnRzX2hla19pbiA8LSBjb3VudHNfaGVrX2luW3doaWNoZ2VuZXNfcmVwcm9kdWNpYmxlKGNvdW50c19oZWtfaW5bLGluZiRCQ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmN1dG9mZiA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwcm9kdWNlY3V0b2ZmID0gMC4xKSwgaW5mJEJDXQpjb3VudHNfaGVrX2V4IDwtIGNvdW50c19oZWtfZXhbd2hpY2hnZW5lc19yZXByb2R1Y2libGUoY291bnRzX2hla19leFssaW5mJEJDXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByY3V0b2ZmID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXByb2R1Y2VjdXRvZmYgPSAwLjEpLCBpbmYkQkNdCgpgYGAKCgojIyB1cHNldCBwbG90IG9mIGludGVyc2VjdGlvbnMKYGBge3J9CgoKYXZlcmFnZV9jb3VudHM8LWRhdGEuZnJhbWUoRU5TRU1CTD1yb3duYW1lcyhjb3VudHNfaGVrX2luZXgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX2NudD1yb3dNZWFucyhjb3VudHNfaGVrX2luZXgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCmludHJvbl9nZW5lczwtcm93bmFtZXMoY291bnRzX2hla19pbikgJT4lIAogIHVuaXF1ZSgpCgpleG9uX2dlbmVzPC1yb3duYW1lcyhjb3VudHNfaGVrX2V4KSU+JSAKICB1bmlxdWUoKQoKdXBzZXRfZGY8LWRhdGEuZnJhbWUoRU5TRU1CTD1jKGV4b25fZ2VuZXMsaW50cm9uX2dlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgIGRldGVjdGlvbj1jKHJlcCgiZXhvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZXM9bGVuZ3RoKGV4b25fZ2VuZXMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImludHJvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVzPWxlbmd0aChpbnRyb25fZ2VuZXMpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JSAKICBsZWZ0X2pvaW4oYmlvdHlwZSxieT1jKCJFTlNFTUJMIj0iZW5zZW1ibF9nZW5lX2lkIikpICU+JSAKICBtdXRhdGUoYmlvdHlwZTI9Y2FzZV93aGVuKGdyZXBsKGdlbmVfYmlvdHlwZSxwYXR0ZXJuPSIqcHNldWRvZ2VuZSIpfiAicHNldWRvZ2VuZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUscGF0dGVybj0iSUcqIil+ICJwcm90ZWluIGNvZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUscGF0dGVybj0iVFIqIil+ICJwcm90ZWluIGNvZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUscGF0dGVybj0iTVQqIil+ICJvdGhlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUscGF0dGVybj0iXnMiKX4gInNtYWxsIFJOQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChnZW5lX2Jpb3R5cGUscGF0dGVybj0icmlib3p5bWUiKX4gIm90aGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9iaW90eXBlPT0ibWlzY19STkEifiAib3RoZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2Jpb3R5cGU9PSJwcm90ZWluX2NvZGluZyJ+ICJwcm90ZWluIGNvZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFR+Z2VuZV9iaW90eXBlKSkgJT4lIAogIGZpbHRlcighaXMubmEoYmlvdHlwZTIpKSAlPiUgCiAgaW5uZXJfam9pbihhdmVyYWdlX2NvdW50cykKCnVwc2V0X2RmJGJpb3R5cGUyPC1mYWN0b3IodXBzZXRfZGYkYmlvdHlwZTIsbGV2ZWxzPXJldihjKCJwcm90ZWluIGNvZGluZyIsImxuY1JOQSIsInBzZXVkb2dlbmUiLCJyUk5BIiwic21hbGwgUk5BIiwibWlSTkEiLCJvdGhlciIpKSkKCgp1cHNldF9kZjwtdXBzZXRfZGYgJT4lIAogIG11dGF0ZSh2YWx1ZT1UUlVFKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGRldGVjdGlvbix2YWx1ZXNfZnJvbSA9IHZhbHVlLHZhbHVlc19maWxsID0gRkFMU0UpICU+JSAKICBsZWZ0X2pvaW4oZ2VuZV90eXBlKQoKY2F0ZWdvcmllczwtYygiZXhvbiIsImludHJvbiIpCiAKdXBzZXQ8LXVwc2V0KHVwc2V0X2RmLAogICAgICBjYXRlZ29yaWVzLAogICAgICBuYW1lPSJHZW5lIGRldGVjdGlvbiIsCiAgICAgIGJhc2VfYW5ub3RhdGlvbnM9bGlzdCgKICAgICAgICAnSW50ZXJzZWN0aW9uIHNpemUnPWludGVyc2VjdGlvbl9zaXplKAogICAgICAgICAgICBjb3VudHM9RkFMU0UsCiAgICAgICAgICAgIG1hcHBpbmc9YWVzKGZpbGw9YmlvdHlwZTIpCiAgICAgICAgICAgIAogICAgICAgICkrc2NhbGVfZmlsbF9ucGcoKQogICAgICAgICtsYWJzKGZpbGw9IiIpCiAgICAgICksCiAgICAgIGFubm90YXRpb25zID0gbGlzdCgKICAgICAgICAnblVNSSc9KAogICAgICAgICAgICBnZ3Bsb3QobWFwcGluZz1hZXMoeT1tZWFuX2NudCxmaWxsPWJpb3R5cGUyKSkKICAgICAgICAgICAgK2dlb21fYm94cGxvdChwb3NpdGlvbj0iZG9kZ2UiLG91dGxpZXIuc2hhcGUgPSBOQSxzaG93LmxlZ2VuZCA9IEYpCiAgICAgICAgICAgICtzY2FsZV95X2xvZzEwKCkKICAgICAgICAgICAgK3NjYWxlX2ZpbGxfbnBnKCkKICAgICAgKSkpCgp1cHNldAoKCmdnc2F2ZSh1cHNldCwKICAgICAgIGRldmljZSA9ICJwZGYiLAogICAgICAgcGF0aCA9IGZpZ19wYXRoLAogICAgICAgd2lkdGggPSAxNTAsCiAgICAgICBoZWlnaHQ9MTgwLAogICAgICAgdW5pdHMgPSAibW0iLAogICAgICAgZmlsZW5hbWUgPSAidXBzZXRfcGxvdC5wZGYiCiAgICAgICApCmBgYAoKCiMjIFN1bW1hcnkgc3RhdHMKYGBge3J9CgptYWtlX3N1bW1hcnk8LWZ1bmN0aW9uKG1hdCx0eXBlKXsKICBkYXRhLmZyYW1lKEJDPWNvbG5hbWVzKG1hdCksCiAgICAgICAgICAgICB1bWk9Y29sU3VtcyhtYXQpLAogICAgICAgICAgICAgZ2VuZT1jb2xTdW1zKG1hdD4wKSwKICAgICAgICAgICAgIHR5cGU9dHlwZSkKfQoKCgpzdW1tYXJ5PC1yYmluZChtYWtlX3N1bW1hcnkoY291bnRzX2hla19leF9vLCJFeG9uIiksCiAgICAgIG1ha2Vfc3VtbWFyeShjb3VudHNfaGVrX2luX28sIkludHJvbiIpLAogICAgICBtYWtlX3N1bW1hcnkoY291bnRzX2hla19pbmV4X28sIkJvdGgiKSkKCnN1bW1hcnkkZXhjbHVzaXZlPC0ieWVzIgoKZ2dwbG90KHN1bW1hcnksYWVzKHk9dW1pLHg9dHlwZSxjb2w9dHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogIGdlb21fYmVlc3dhcm0oKSsKICBzY2FsZV95X2xvZzEwKCkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9aW5leF9jb2xvcnMsbGltaXRzPWZvcmNlKQoKZ2dwbG90KHN1bW1hcnksYWVzKHk9Z2VuZSx4PXR5cGUsY29sPXR5cGUpKSsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2JlZXN3YXJtKCkrCiAgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWluZXhfY29sb3JzLGxpbWl0cz1mb3JjZSkKCgpzdW1tYXJ5MjwtcmJpbmQobWFrZV9zdW1tYXJ5KGNvdW50c19oZWtfZXgsIkV4b24iKSwKICAgICAgbWFrZV9zdW1tYXJ5KGNvdW50c19oZWtfaW4sIkludHJvbiIpLAogICAgICBtYWtlX3N1bW1hcnkoY291bnRzX2hla19pbmV4LCJCb3RoIikpCgpzdW1tYXJ5MiRleGNsdXNpdmU8LSJubyIKCmdncGxvdChzdW1tYXJ5MixhZXMoeT11bWkseD10eXBlLGNvbD10eXBlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgZ2VvbV9iZWVzd2FybSgpKwogIHNjYWxlX3lfbG9nMTAoKSsKICBnZ3RpdGxlKCIiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1pbmV4X2NvbG9ycyxsaW1pdHM9Zm9yY2UpCgpnZ3Bsb3Qoc3VtbWFyeTIsYWVzKHk9Z2VuZSx4PXR5cGUsY29sPXR5cGUpKSsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2JlZXN3YXJtKCkrCiAgc2NhbGVfeV9sb2cxMCgpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWluZXhfY29sb3JzLGxpbWl0cz1mb3JjZSkKCnN1bW1hcnkzPC1yYmluZChzdW1tYXJ5LHN1bW1hcnkyKSAjJT4lIAogIyBwaXZvdF9sb25nZXIoY29scz1jKHVtaSxnZW5lKSxuYW1lc190byA9ICJ0eXBlMiIgLHZhbHVlc190byA9ICJjb3VudCIpIAoKCmdncGxvdChzdW1tYXJ5MyxhZXModHlwZSx5PWdlbmUsZ3JvdXA9cGFzdGUwKGV4Y2x1c2l2ZSx0eXBlKSxjb2w9ZXhjbHVzaXZlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgZ2VvbV9iZWVzd2FybShkb2RnZS53aWR0aCA9IDAuODApKwogIHNjYWxlX3lfbG9nMTAoKQoKZ2dwbG90KHN1bW1hcnkzLGFlcyh0eXBlLHk9dW1pLGdyb3VwPXBhc3RlMChleGNsdXNpdmUsdHlwZSksY29sPWV4Y2x1c2l2ZSkpKwogIGdlb21fYm94cGxvdCgpKwogIGdlb21fYmVlc3dhcm0oZG9kZ2Uud2lkdGggPSAwLjgwKSsKICBzY2FsZV95X2xvZzEwKCkKCgoKYGBgCgoKYGBge3J9CmluZXhfZ2VuZXM8LXJvd25hbWVzKGNvdW50c19oZWtfaW5leCkKCiMgc3Vic2V0IGZvciBnZW5lcyBleHByZXNzZWQgaW4gYm90aApleG9uPC1jb3VudHNfaGVrX2V4W3Jvd25hbWVzKGNvdW50c19oZWtfZXgpJWluJWluZXhfZ2VuZXMsXSAKZXhvbjwtZXhvblt3aGljaGdlbmVzX3JlcHJvZHVjaWJsZShleG9uLDUscmVwcm9kdWNlY3V0b2ZmID0gMC4yKSxdIApleG9uPC1leG9uWyxdIAoKaW50cm9uPC1jb3VudHNfaGVrX2luW3Jvd25hbWVzKGNvdW50c19oZWtfaW4pJWluJWluZXhfZ2VuZXMsXQppbnRyb248LWludHJvblt3aGljaGdlbmVzX3JlcHJvZHVjaWJsZShpbnRyb24sNSxyZXByb2R1Y2VjdXRvZmYgPSAwLjIpLF0gCgppbmV4X2xpYjwtZGF0YS5mcmFtZShzYW1wbGU9bmFtZXMoY29sU3Vtcyhjb3VudHNfaGVrX2luZXgpKSwKICAgICAgICAgICBMaWJTaXplPWNvbFN1bXMoY291bnRzX2hla19pbmV4KSkKCiMjIG5vcm1hbGl6ZSB0byBVTUkgcGVyIG1pbGxpb24KCnVwbTwtZnVuY3Rpb24odW1pX2NvdW50cyl7IAogIHVtaV9jb3VudHMlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhcj0iR2VuZUlEIikgJT4lCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gMjpuY29sKC4pLAogICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2FtcGxlIiwKICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJjbnQiKSAlPiUKICBsZWZ0X2pvaW4oaW5leF9saWIpICU+JSAKICBncm91cF9ieShzYW1wbGUpICU+JQogIG11dGF0ZSh1cG0gPSBjbnQgLyBMaWJTaXplICoxZTYgKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jKExpYlNpemUsY250KSklPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2FtcGxlLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gdXBtKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIkdlbmVJRCIpICU+JQogIGFzLm1hdHJpeCgpCn0KCmV4b25fdXBtPC11cG0oZXhvbikKZXhvbl91cG08LWxvZzIoZXhvbl91cG0rMSkKaGVhZChleG9uX3VwbSkKCmludHJvbl91cG08LXVwbShpbnRyb24pCmludHJvbl91cG08LWxvZzIoaW50cm9uX3VwbSsxKQpoZWFkKGludHJvbl91cG0pCgpkZjwtZGF0YS5mcmFtZShFTlNFTUJMPXJvd25hbWVzKGV4b25fdXBtKSxleG9uPXJvd01lYW5zKGV4b25fdXBtKSkgJT4lIAogIGlubmVyX2pvaW4oZGF0YS5mcmFtZShFTlNFTUJMPXJvd25hbWVzKGludHJvbl91cG0pLGludHJvbj1yb3dNZWFucyhpbnRyb25fdXBtKSkpICU+JSAKICBpbm5lcl9qb2luKGdlbmVfdHlwZSkgJT4lIAogIGZpbHRlcihiaW90eXBlMiVpbiVjKCJwcm90ZWluIGNvZGluZyIpKSAlPiUgCiAgdW5pcXVlKCkKICAKCgoKc21jX2luZXg8LWdncGxvdChkZikgKyBhZXMoeD1leG9uLCB5PWludHJvbikrIAogIHN0YXRfZGVuc2l0eTJkKGdlb209InRpbGUiLCBhZXMoZmlsbD0uLmRlbnNpdHkuLl4wLjI1LCBhbHBoYT0xKSwgY29udG91cj1GQUxTRSxzaG93LmxlZ2VuZCA9IEYpICsgCiAgZ2VvbV9wb2ludChzaXplPTAuNSxzaG93LmxlZ2VuZCA9IEYpICsKICBzdGF0X2RlbnNpdHkyZChnZW9tPSJ0aWxlIiwgYWVzKGZpbGw9Li5kZW5zaXR5Li5eMC4yNSwgICAgIGFscGhhPWlmZWxzZSguLmRlbnNpdHkuLl4wLjI1PDAuMTUsMCwxKSksIGNvbnRvdXI9RkFMU0Usc2hvdy5sZWdlbmQgPSBGKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnMgPSBjb2xvclJhbXBQYWxldHRlKGMoIndoaXRlIiwgYmx1ZXM5LCJibGFjayIpKSgyNTYpKSsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSsKICBnZW9tX3Ntb290aChhZXMoZXhvbixpbnRyb24pLG1ldGhvZD0ibG0iLGNvbD0iZ3JleTcwIikrCiAgbGFicyh4PSJMb2cgTWVhbiBleHByZXNzaW9uIEV4b24iLHk9IkxvZyBNZWFuIGV4cHJlc3Npb24gSW50cm9uIikKCnNtY19pbmV4CgpoaXN0LmluZXg8LWRmICU+JSAgCiAgcmVuYW1lKEV4b249ZXhvbiwKICAgICAgICAgSW50cm9uPWludHJvbikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYygiRXhvbiIsIkludHJvbiIpKSAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHZhbHVlLGZpbGw9bmFtZSksYWxwaGE9MC44LGNvbG91cj0iZ3JleTUwIixiaW5zID0gNTApKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGluZXhfY29sb3JzLGxpbWl0cz1mb3JjZSkrCiAgbGFicyh4PSJMb2cgTWVhbiBFeHByZXNzaW9uIiwKICAgICAgIGZpbGw9IiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuNSksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgoKaGlzdC5pbmV4CgpnZ3NhdmUoc21jX2luZXgsCiAgICAgICBkZXZpY2UgPSAicGRmIiwKICAgICAgIHBhdGggPSBmaWdfcGF0aCwKICAgICAgIHdpZHRoID0gMTAwLAogICAgICAgaGVpZ2h0PTEwMCwKICAgICAgIHVuaXRzID0gIm1tIiwKICAgICAgIGZpbGVuYW1lID0gInNjYXR0ZXJfcGxvdC5wZGYiCiAgICAgICApCgpnZ3NhdmUoaGlzdC5pbmV4LAogICAgICAgZGV2aWNlID0gInBkZiIsCiAgICAgICBwYXRoID0gZmlnX3BhdGgsCiAgICAgICB3aWR0aCA9IDEwMCwKICAgICAgIGhlaWdodD0xMDAsCiAgICAgICB1bml0cyA9ICJtbSIsCiAgICAgICBmaWxlbmFtZSA9ICJleHBfZGlzdF9wbG90LnBkZiIKICAgICAgICkKYGBgCiMjIHJhbmtlZCBleG9uIHZzLiBpbnRyb24gZXhwcmVzc2lvbgoKYGBge3J9CgpyYW5rX21hdDwtZnVuY3Rpb24oY291bnRfbWF0KXsgCiAgY291bnRfbWF0JT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXI9IkdlbmVJRCIpICU+JQogIHBpdm90X2xvbmdlciggY29scyA9IDI6bmNvbCguKSwKICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNhbXBsZSIsCiAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiY250IikgJT4lCiAgYXJyYW5nZShHZW5lSUQsY250KSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUKICBtdXRhdGUoZ2VuZV9yYW5rID0gcmFuayhjbnQpKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLWNudCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGUsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBnZW5lX3JhbmspICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiR2VuZUlEIikgJT4lCiAgYXMubWF0cml4KCkKICAgIAp9CgpleG9uX3Jhbms8LXJhbmtfbWF0KGV4b24pCgppbnRyb25fcmFuazwtcmFua19tYXQoaW50cm9uKQoKZGZfcmFuazwtZGF0YS5mcmFtZShFTlNFTUJMPXJvd25hbWVzKGV4b25fcmFuayksCiAgICAgICAgICAgICAgICAgICAgZXhvbl9yYW5rPXJvd01lYW5zKGV4b25fcmFuaykpICU+JSAKICBpbm5lcl9qb2luKGRhdGEuZnJhbWUoRU5TRU1CTD1yb3duYW1lcyhpbnRyb25fcmFuayksCiAgICAgICAgICAgICAgICAgICAgICAgIGludHJvbl9yYW5rPXJvd01lYW5zKGludHJvbl9yYW5rKSkpICU+JSAKICBpbm5lcl9qb2luKGRmKSAlPiUgCiAgZmlsdGVyKGJpb3R5cGUyJWluJWMoInByb3RlaW4gY29kaW5nIiwibG5jUk5BIikpICU+JSAKICBtdXRhdGUobm9ybV9yYW5rX2V4b249ZXhvbl9yYW5rL21heChleG9uX3JhbmspLAogICAgICAgICBub3JtX3JhbmtfaW50cm9uPWludHJvbl9yYW5rL21heChpbnRyb25fcmFuaykpCiAgCiAgZ2dwbG90KGRmX3JhbmspKwogIGdlb21fZGVuc2l0eTJkX2ZpbGxlZChhZXMoZXhvbl9yYW5rLGludHJvbl9yYW5rKSwpKwogIGdlb21fc21vb3RoKGFlcyhleG9uX3JhbmssaW50cm9uX3JhbmspLG1ldGhvZD0ibG0iKSsKICBmYWNldF93cmFwKH5iaW90eXBlMixucm93PTIsc2NhbGVzPSJmcmVlIikKICAKICAgIGdncGxvdChkZl9yYW5rKSsKICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoYWVzKG5vcm1fcmFua19leG9uLG5vcm1fcmFua19pbnRyb24pLHNpemU9MC4yKSsKICBnZW9tX3Ntb290aChhZXMobm9ybV9yYW5rX2V4b24sbm9ybV9yYW5rX2ludHJvbiksbWV0aG9kPSJsbSIpKwogIGZhY2V0X3dyYXAofmJpb3R5cGUyLG5yb3c9MixzY2FsZXM9ImZyZWUiKQoKCiAgICAKYGBgCgojIEludHJvbiB2cy4gRXhvbiBtYXBwaW5nCgoKMTogc3Vic2V0IC5iYW0gZmlsZSBmb3IgYmFyY29kZXMKMjogcnVuIGdldDNkaXN0YW5jZV92M19TUF92Mi5SIGZvciBpbnRyb24gYW5kIGZvciBleG9uIHNlcGFyYXRlbHkKMzogY29tYmluZSBvdXRwdXRzIGFuZCBwbG90CgpgYGB7cn0KCmJhbV9wYXRoPC0gIi9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvRmlnX2JlYWRzX2NvbHVtbnMvelVNSXMvSEVLL3pVTUlzX291dHB1dC9kZW11bHRpcGxleGVkLyIKCmJhbV9maWxlczwtbGlzdC5maWxlcyhwYXRoID0gYmFtX3BhdGgscGF0dGVybiA9ICIuYmFtJCIpCgpiY3M8LWluZiRYQwoKYmFtX2ZpbGVzPC1iYW1fZmlsZXNbc3RyX3NwbGl0KGJhbV9maWxlcyxwYXR0ZXJuID0gIlsuXSIsc2ltcGxpZnkgPSBUKVssMl0gJWluJSBiY3NdCgoKYGBgCgojIGdldCBwZXIgYmFtIGZpbGUgZ2VuZUJvZHkgY292ZXJhZ2UKCmBgYHtyfQojIGxpYnJhcnkoR2Vub21pY1JhbmdlcywgcXVpZXRseT1ULCB3YXJuLmNvbmZsaWN0cyA9IEYpCiMgbGlicmFyeShHZW5vbWljRmVhdHVyZXMsIHF1aWV0bHk9VCwgd2Fybi5jb25mbGljdHMgPSBGKQojIGxpYnJhcnkoR2Vub21pY0FsaWdubWVudHMsIHF1aWV0bHk9VCwgd2Fybi5jb25mbGljdHMgPSBGKQojIAojICMjIElucHV0czoKIyAjYmFtX2ZpbGVzICN3aXRoIGNvcnJlc3BvbmRpbmcgLmJhaQojICNvdXQgIyJuYW1lIGJhc2UgZm9yIHBsb3QgYW5kIG91dHRhYmxlIgojIGNvdW50c19oZWtfaW5leDwtY291bnRzX2hlayR1bWljb3VudCRpbmV4JGFsbCAlPiUgYXMubWF0cml4KCkKIyBjb3VudHNfaGVrX2luZXg8LWNvdW50c19oZWtfaW5leFssaW5mJEJDXQojIAojIGluZXhfZ2VuZXM8LXJvd25hbWVzKGNvdW50c19oZWtfaW5leCkKIyAKIyBpbmV4X2dlbmVzPC1pbmV4X2dlbmVzW29yZGVyKHJvd1N1bXMoY291bnRzX2hla19pbmV4KSxkZWNyZWFzaW5nID0gVCldICMgc29ydCBieSBoaWdoZXN0IG92ZXJhbGwgY291bnQKIyAKIyBnZW5lcyA8LSBpbmV4X2dlbmVzWzE6MjAwMF0gI2lmIHlvdSB3YW50IHRvIHN1YnNldCBnZW5lcywgbGlzdCBvZiBFTlNHIGlkcwojIHdyaXRlLnRhYmxlKGdlbmVzLHBhc3RlMChiYW1fcGF0aCwiaW5leC5nZW5lcy50eHQiKSxxdW90ZSA9IEYscm93Lm5hbWVzID0gRixjb2wubmFtZXMgPSBGKQojIGdlbmVzPC1wYXN0ZTAoYmFtX3BhdGgsImluZXguZ2VuZXMudHh0IikKIyAKIyAjZnR5cGUiICMiaW50cm9uIG9yIGV4b24iCiMgCiMgZ3RmX2ZpbGU8LSAiL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuY29kZS52MzUucHJpbWFyeV9hc3NlbWJseS5hbm5vdGF0aW9uLmd0ZiIgI2d0ZiBmaWxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zY3JpcHQgaW5mbyIKIyB0eGRiIDwtIG1ha2VUeERiRnJvbUdGRihndGZfZmlsZSwgZm9ybWF0PSJndGYiKQojIAojICMgcmVzdHJpY3QgdG8gY2Fub25pY2FsIGNocm9tb3NvbWVzCiMgCiMgY2Fub25pY2FsX2Nocjwtc2VxbGV2ZWxzKHR4ZGIpWzE6MjVdCiMgCiMgCiMgdG1wPC10cmFuc2NyaXB0c0J5KHR4ZGIsIGJ5PSJnZW5lIikKIyBnZW5lMnRyYW5zY3JpcHQ8LWxhcHBseSggdG1wLCBmdW5jdGlvbih4KXsgIG1jb2xzKHgpJHR4X25hbWUgfSkKIyAKIyBzYXZlRGIodHhkYiwgZmlsZT0iL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuY29kZS52MzUucHJpbWFyeV9hc3NlbWJseS5zcWxpdGUiKQojIHNhdmUoZ2VuZTJ0cmFuc2NyaXB0LGZpbGU9Ii9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvZ2Vub21lcy9Ic2FwL2dlbmUydHJhbnNjcmlwdF9jYW5vbmljYWwuUmRhdGEiICkKIyAKIyB0eGRiPC0iL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuY29kZS52MzUucHJpbWFyeV9hc3NlbWJseS5zcWxpdGUiCiMgZzJ0PC0iL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuZTJ0cmFuc2NyaXB0X2Nhbm9uaWNhbC5SZGF0YSIKIyAKIyBtYXhUZGlzdCA8LSAxMDAwMCAjIm1heCBkaXN0LiB0byAzJyBlbmQgY291bnRlZCIKIyBtaW5UbGVuZ3RoIDwtIDAgICMibWluaW1hbCBsZW5ndGggb2YgdHJhbnNjcmlwdHMgY29uc2lkZXJlZCIKIyBtYXhfZXhvbl9sZW5ndGg8LSA1MDAwICMgbWF4IGxlbmd0aCBvZiBleG9ucyBwZXIgZ2VuZQojIG5nZW5lczwtIDIwMDAgI21heCBudW1iZXIgb2YgZ2VuZXMgdG8gdXNlCiMgCiMgIyBpPSJIRUsuQUNUR0FHQ0dBQUFBQ1QuZGVteC5iYW0iCiMgIyBqPSJpbnRyb24iCiMgCiMgIyBpbmRleAojICBmb3IgKGkgaW4gYmFtX2ZpbGVzKXsKIyAgICBpZiAoIShmaWxlLmV4aXN0cyhwYXN0ZTAoYmFtX3BhdGgsaSwiLmJhaSIpKSkpCiMgCiMgICAgIyBpbmRleCBiYW0gZmlsZQojICAgc3lzdGVtKHBhc3RlMCgic2FtdG9vbHMgaW5kZXggIixiYW1fcGF0aCxpKSkKIyAKIyAgfQojIAojIAojICMjIHN0YXJ0IHNsdXJtIGpvYnMKIyAgZm9yIChpIGluIGJhbV9maWxlcyl7CiMgICAgZm9yIChqIGluIGMoImV4b24iLCJpbnRyb24iKSl7CiMgICBvdXQ8LSBzdHJfc3BsaXQoaSxwYXR0ZXJuID0gIlsuXSIsc2ltcGxpZnkgPSBUKVssMl0KIyAKIyAKIyAgIHN5c3RlbSgKIyAgICAgcGFzdGUwKAojICAgICAgICJzYmF0Y2ggLUogIiwKIyAgICAgICBvdXQsCiMgICAgICAgIiAtLXdyYXAgJy9vcHQvYmluL1JzY3JpcHQiLAojICAgICAgICIgL2RhdGEvc2hhcmUvY29tbW9uL3NjcmlwdHMvZ2V0M2Rpc3RhbmNlX3YzX1NQX3YyX0xXX3YxLlIiLAojICAgICAgICIgLS1iYW1maWxlICIsCiMgICAgICAgcGFzdGUwKGJhbV9wYXRoLCBpKSwKIyAgICAgICAiIC0tdHhkYiAiLAojICAgICAgIHR4ZGIsCiMgICAgICAgIiAtLWcydG1hcHBpbmcgIiwKIyAgICAgICBnMnQsCiMgICAgICAgIiAtLW91dCAiLAojICAgICAgIHBhc3RlMChvdXQsIl8iLCBqKSwKIyAgICAgICAiIC0tbWluVGxlbmd0aCAiLAojICAgICAgIG1pblRsZW5ndGgsCiMgICAgICAgIiAtLW1heF9leG9uX2xlbmd0aCAiLAojICAgICAgIG1heF9leG9uX2xlbmd0aCwKIyAgICAgICAiIC0tZnR5cGUgIiwKIyAgICAgICBqLAojICAgICAgICIgLS1wbG90IEYgIiwKIyAgICAgICAiIC0tY2Fub25pY2FsIFQgIiwKIyAgICAgICAiIC0tZ2VuZXMgIiwKIyAgICAgICBnZW5lcywKIyAgICAgICAiIC0tbmdlbmVzICIsCiMgICAgICAgbmdlbmVzLAojICAgICAgICInIgojICAgICApCiMgICApCiMgCiMgfX0KIyAKCgpgYGAKCiMjIHNhbWUgZm9yIGludHJvbiBvbmx5IGdlbmVzCmBgYHtyfQoKY291bnRzX2hla19pbl9vPC1jb3VudHNfaGVrX2luX29bLGluZiRCQ10KCmludHJvbl9vbmx5X2dlbmVzIDwtdW5pcXVlKHJvd25hbWVzKGNvdW50c19oZWtfaW5fbykpCgppbnRyb25fb25seV9nZW5lczwtaW50cm9uX29ubHlfZ2VuZXNbb3JkZXIocm93U3Vtcyhjb3VudHNfaGVrX2luX29baW50cm9uX29ubHlfZ2VuZXMsXSksZGVjcmVhc2luZyA9IFQpXSAjIHNvcnQgYnkgaGlnaGVzdCBvdmVyYWxsIGNvdW50CgpnZW5lcyA8LSBpbnRyb25fb25seV9nZW5lc1sxOjIwMDBdICNpZiB5b3Ugd2FudCB0byBzdWJzZXQgZ2VuZXMsIGxpc3Qgb2YgRU5TRyBpZHMKd3JpdGUudGFibGUoZ2VuZXMscGFzdGUwKGJhbV9wYXRoLCJpbnRyb25fb25seS5nZW5lcy50eHQiKSxxdW90ZSA9IEYscm93Lm5hbWVzID0gRixjb2wubmFtZXMgPSBGKQpnZW5lczwtcGFzdGUwKGJhbV9wYXRoLCJpbnRyb25fb25seS5nZW5lcy50eHQiKQoKZ3RmX2ZpbGU8LSAiL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuY29kZS52MzUucHJpbWFyeV9hc3NlbWJseS5hbm5vdGF0aW9uLmd0ZiIgI2d0ZiBmaWxlIGNvbnRhaW5pbmcgdGhlIHRyYW5zY3JpcHQgaW5mbyIKdHhkYjwtIi9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvZ2Vub21lcy9Ic2FwL2dlbmNvZGUudjM1LnByaW1hcnlfYXNzZW1ibHkuc3FsaXRlIgpnMnQ8LSIvZGF0YS9zaGFyZS9odHAvcHJpbWUtc2VxX1BhcGVyL2dlbm9tZXMvSHNhcC9nZW5lMnRyYW5zY3JpcHRfY2Fub25pY2FsLlJkYXRhIgoKbWF4VGRpc3QgPC0gMTAwMDAgIyJtYXggZGlzdC4gdG8gMycgZW5kIGNvdW50ZWQiCm1pblRsZW5ndGggPC0gMCAgIyJtaW5pbWFsIGxlbmd0aCBvZiB0cmFuc2NyaXB0cyBjb25zaWRlcmVkIgptYXhfZXhvbl9sZW5ndGg8LSA1MDAwICMgbWF4IGxlbmd0aCBvZiBleG9ucyBwZXIgZ2VuZQpuZ2VuZXM8LSAyMDAwICNtYXggbnVtYmVyIG9mIGdlbmVzIHRvIHVzZQoKIyBpPSJIRUsuQUNUR0FHQ0dBQUFBQ1QuZGVteC5iYW0iCgoKIyMgc3RhcnQgc2x1cm0gam9icwogZm9yIChpIGluIGJhbV9maWxlcyl7CiAgb3V0PC0gc3RyX3NwbGl0KGkscGF0dGVybiA9ICJbLl0iLHNpbXBsaWZ5ID0gVClbLDJdCgoKICBzeXN0ZW0oCiAgICBwYXN0ZTAoCiAgICAgICJzYmF0Y2ggLUogIiwKICAgICAgb3V0LAogICAgICAiIC0td3JhcCAnL29wdC9iaW4vUnNjcmlwdCIsCiAgICAgICIgL2RhdGEvc2hhcmUvY29tbW9uL3NjcmlwdHMvZ2V0M2Rpc3RhbmNlX3YzX1NQX3YyX0xXX3YxLlIiLAogICAgICAiIC0tYmFtZmlsZSAiLAogICAgICBwYXN0ZTAoYmFtX3BhdGgsIGkpLAogICAgICAiIC0tdHhkYiAiLAogICAgICB0eGRiLAogICAgICAiIC0tZzJ0bWFwcGluZyAiLAogICAgICBnMnQsCiAgICAgICIgLS1vdXQgIiwKICAgICAgcGFzdGUwKG91dCwiXyIsICJpbnRyb25fb25seSIpLAogICAgICAiIC0tbWluVGxlbmd0aCAiLAogICAgICBtaW5UbGVuZ3RoLAogICAgICAiIC0tbWF4X2V4b25fbGVuZ3RoICIsCiAgICAgIG1heF9leG9uX2xlbmd0aCwKICAgICAgIiAtLWZ0eXBlICIsCiAgICAgICJpbnRyb24iLAogICAgICAiIC0tcGxvdCBGICIsCiAgICAgICIgLS1jYW5vbmljYWwgVCAiLAogICAgICAiIC0tZ2VuZXMgIiwKICAgICAgZ2VuZXMsCiAgICAgICIgLS1uZ2VuZXMgIiwKICAgICAgbmdlbmVzLAogICAgICAiJyIKICAgICkKICApCgp9CgoKCmBgYAoKCmBgYHtyfQoKdGFibGVzPC1saXN0LmZpbGVzKHBhc3RlMChmaWdfcGF0aCwiL2dlbmVib2R5X2NvdmVyYWdlLyIpLHBhdHRlcm49Im9uLnR4dCIpCnRhYmxlczwtYyh0YWJsZXMsbGlzdC5maWxlcyhwYXN0ZTAoZmlnX3BhdGgsIi9nZW5lYm9keV9jb3ZlcmFnZS8iKSxwYXR0ZXJuPSJpbnRyb25fb25seS50eHQiKSkKCgoKZm9yIChpIGluIHRhYmxlcyl7CiAgaWYoIShleGlzdHMoImNvbWJpbmVkIikpKXsKICAgIGNvbWJpbmVkPC1yZWFkX2RlbGltKHBhc3RlMChmaWdfcGF0aCwiL2dlbmVib2R5X2NvdmVyYWdlLyIsaSksCiAgICAgICAgICAgICAgICAgICAgICAgICBkZWxpbSA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUgCiAgICAgIG11dGF0ZShCQz1zdHJfc3BsaXQoaSxwYXR0ZXJuPWMoIl8iKSxzaW1wbGlmeSA9IFQpWywxXSwKICAgICAgICAgICAgIHR5cGU9c3RyX3NwbGl0KHN0cl9zcGxpdF9maXhlZChpLHBhdHRlcm49YygiXyIpLG4gPSAyKVssMl0scGF0dGVybj0iWy5dIixzaW1wbGlmeT1UKVssMV0pCiAgICAKICB9ZWxzZXsKICAgIGNvbWJpbmVkPC1yZWFkX2RlbGltKHBhc3RlMChmaWdfcGF0aCwiL2dlbmVib2R5X2NvdmVyYWdlLyIsaSksZGVsaW0gPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lIAogICAgICAgbXV0YXRlKEJDPXN0cl9zcGxpdChpLHBhdHRlcm49YygiXyIpLHNpbXBsaWZ5ID0gVClbLDFdLAogICAgICAgICAgICAgdHlwZT1zdHJfc3BsaXQoc3RyX3NwbGl0X2ZpeGVkKGkscGF0dGVybj1jKCJfIiksbiA9IDIpWywyXSxwYXR0ZXJuPSJbLl0iLHNpbXBsaWZ5PVQpWywxXSkgJT4lIAogICAgICBiaW5kX3Jvd3MoY29tYmluZWQpCiAgfQogIAp9CgoKY29tYmluZWRfc3VtPC1jb21iaW5lZCAlPiUgCiAgZ3JvdXBfYnkoZGlzdGFuY2VfdG9fM19lbmQsdHlwZSkgJT4lIAogIHN1bW1hcml6ZSh0b3RhbF9jb3VudD1zdW0ocmVhZF9udW1iZXIpKSAlPiUKICBncm91cF9ieSh0eXBlKSAlPiUgCiAgZmlsdGVyKHRvdGFsX2NvdW50PjApICU+JSAKICBmaWx0ZXIoZGlzdGFuY2VfdG9fM19lbmQ8NTAwMCkgJT4lIAogIG11dGF0ZShzY2FsZWRfY291bnQ9KHRvdGFsX2NvdW50L3N1bSh0b3RhbF9jb3VudCkpKjFlNikgJT4lIAogIG11dGF0ZSh0eXBlPWNhc2Vfd2hlbih0eXBlPT0iZXhvbiJ+IkV4b24iLAogICAgICAgICAgICAgICAgICAgICAgICB0eXBlPT0iaW50cm9uIn4iSW50cm9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgVH4gIkludHJvbiBvbmx5IikpCgpnZ3Bsb3QoY29tYmluZWRfc3VtLCBhZXMoeD1kaXN0YW5jZV90b18zX2VuZCwgeT10b3RhbF9jb3VudCxjb2w9dHlwZSkpICsgCiAgZ2VvbV9zbW9vdGgoKSsKICAjc2NhbGVfeV9sb2cxMCgpICsKICBzY2FsZV94X3JldmVyc2UoKSArCiAgdGhlbWVfbWluaW1hbCgpKwogICAgZmFjZXRfd3JhcCh+dHlwZSxzY2FsZXM9ImZyZWUiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1pbmV4X2NvbG9ycyxsaW1pdHM9Zm9yY2UpCiAgCnBfZW5yaWNoPC1nZ3Bsb3QoY29tYmluZWRfc3VtLCBhZXMoeD1kaXN0YW5jZV90b18zX2VuZCwgeT1zY2FsZWRfY291bnQsY29sPXR5cGUpKSArIAogIGdlb21fc21vb3RoKCkrCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgc2NhbGVfeF9yZXZlcnNlKGxpbWl0cz1jKDUwMDAsMCkpICsKICBsYWJzKHg9ICJEaXN0YW5jZSB0byAzIHByaW1lIGVuZCIgLAogICAgICAgeT0gIkNvdW50cyBwZXIgcG9zaXRpb24gcGVyIG1pbGxpb24iLAogICAgICAgY29sb3VyPSIiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1pbmV4X2NvbG9ycyxsaW1pdHM9Zm9yY2UpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4zLDAuNyksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCiAgCgpwX2VucmljaAoKZ2dzYXZlKHBfZW5yaWNoLAogICAgICAgZGV2aWNlID0gInBkZiIsCiAgICAgICBwYXRoID0gZmlnX3BhdGgsCiAgICAgICB3aWR0aCA9IDE4MCwKICAgICAgIGhlaWdodD0xMDAsCiAgICAgICB1bml0cyA9ICJtbSIsCiAgICAgICBmaWxlbmFtZSA9ICJlbnJpY2hfcGxvdC5wZGYiCiAgICAgICApCgpgYGAKIyMjIGNoZWNrIGJhbSBjb3ZlcmFnZSBmb3IgZ2VuZXMgd2l0aCBoaWdoIGludHJvbiBhbmQgZXhvbiBleHByZXNzaW9uCgpgYGB7cn0KdG9wX2dlbmVzX2luZXg8LWRmX3JhbmsgJT4lIAogIGZpbHRlcighKGlzLm5hKGV4dGVybmFsX2dlbmVfbmFtZSkpKSAlPiUgCiAgZmlsdGVyKCEoaXMubmEoY2hyb21vc29tZV9uYW1lKSkpICU+JSAKICBmaWx0ZXIoZXhvbl9yYW5rPDE5NTAwICYgaW50cm9uX3Jhbms+IDE1NTAwKSAlPiUgCiAgYXJyYW5nZShkZXNjKGV4b25fcmFuaykpICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgc2xpY2VfbWF4KGV4b25fcmFuayxuPTIwKQoKY29sbmFtZXMoZXhvbik8LXBhc3RlMChjb2xuYW1lcyhleG9uKSwiX0V4b24iKQpjb2xuYW1lcyhpbnRyb24pPC1wYXN0ZTAoY29sbmFtZXMoaW50cm9uKSwiX0ludHJvbiIpCgoKZnVsbF9tYXQ8LWxpc3Qocm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUoZXhvbiksdmFyPSJHZW5lX0lEIikscm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUoaW50cm9uKSx2YXI9IkdlbmVfSUQiKSkgJT4lIAogIHBseXI6OmpvaW5fYWxsKCkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXI9IkdlbmVfSUQiKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBhcy5tYXRyaXgoKSAKCmZ1bGxfbWF0W2lzLm5hKGZ1bGxfbWF0KV08LTAKCmluZXhfbWF0PC1mdWxsX21hdFssMTc6MzJdK2Z1bGxfbWF0WywxOjE2XQpjb2xuYW1lcyhpbmV4X21hdCk8LXBhc3RlMChzdHJfc3BsaXQoY29sbmFtZXMoaW5leF9tYXQpLHBhdHRlcm4gPSAiXyIsc2ltcGxpZnkgPSBUKVssMV0sIl9Cb3RoIikKCmZ1bGxfbWF0IDwtbGlzdChyb3duYW1lc190b19jb2x1bW4oYXMuZGF0YS5mcmFtZShpbmV4X21hdCksdmFyPSJHZW5lX0lEIikscm93bmFtZXNfdG9fY29sdW1uKGFzLmRhdGEuZnJhbWUoZnVsbF9tYXQpLHZhcj0iR2VuZV9JRCIpKSAlPiUgCiAgcGx5cjo6am9pbl9hbGwoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0iR2VuZV9JRCIpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGFzLm1hdHJpeCgpIAoKCnRvcF9nZW5lc19tYXQ8LWZ1bGxfbWF0W3RvcF9nZW5lc19pbmV4JEVOU0VNQkwsXSAlPiUgCiAgdCgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXI9IlNhbXBsZSIpICU+JSAKICBtdXRhdGUodHlwZT1zdHJfc3BsaXQoU2FtcGxlLHBhdHRlcm4gPSAiXyIsc2ltcGxpZnkgPSBUKVssMl0pCgp0b3BfZ2VuZXNfbWF0JT4lIAogIGRwbHlyOjpzZWxlY3QoYyh0eXBlLHRvcF9nZW5lc19pbmV4JEVOU0VNQkxbMV0pKSAlPiUgCiAgcmVuYW1lKCJFbnNlbWJsIj10b3BfZ2VuZXNfaW5leCRFTlNFTUJMWzFdKSAlPiUgCiAgZ2dwbG90KGFlcyh5PUVuc2VtYmwseD10eXBlLGZpbGw9dHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogIGNvb3JkX2ZsaXAoKSsKICBmYWNldF9ncmlkKHR5cGV+LixzY2FsZT0iZnJlZSIpKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT0gZWxlbWVudF9ibGFuaygpKSsKICBsYWJzKHg9IiIseT1wYXN0ZTAoIlVNSXMgKCIsdG9wX2dlbmVzX2luZXgkZXh0ZXJuYWxfZ2VuZV9uYW1lWzFdLCIpIikpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1pbmV4X2NvbG9ycykKICAKdG9wX2dlbmVzX21hdCR0eXBlPC1mYWN0b3IodG9wX2dlbmVzX21hdCR0eXBlLGxldmVscz1yZXYoYygiSW50cm9uIiwiRXhvbiIsIkJvdGgiKSkpCgpgYGAKCiMgcGxvdCBjb3ZlcmFnZSBmb3IgbW9zdCBoaWdobHkgZXhwcmVzc2VkIGV4b25zIGFuZCBpbnRyb25zCgpgYGB7cn0KCnNvdXJjZSgiL2RhdGEvaG9tZS93YW5nZS9BVEFDL0NvdmVyYWdlX1Bsb3RfZnVuY3Rpb25zX1YxLlIiKQoKZ3RmX2ZpbGU8LSIvZGF0YS9zaGFyZS9odHAvcHJpbWUtc2VxX1BhcGVyL2dlbm9tZXMvSHNhcC9nZW5jb2RlLnYzNS5wcmltYXJ5X2Fzc2VtYmx5LmFubm90YXRpb24uZ3RmIgoKZ3RmPC1ydHJhY2tsYXllcjo6aW1wb3J0LmdmZjIoZ3RmX2ZpbGUpCiMgCiMgR1ZfZ2VuZV9tb2Q8LW1ha2VHdml6X2dlbmVNb2RlbF9mcm9tX2dlbmNvZGUoZ3RmKQojIAojIHNhdmVSRFMoR1ZfZ2VuZV9tb2QsIi9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvZ2Vub21lcy9Ic2FwL2dlbmNvZGUudjM1LnByaW1hcnlfYXNzZW1ibHkuYW5ub3RhdGlvbi5ndGYuZ2VuZW1vZGVsc19HZW5ldml6LnJkcyIpCgpHVl9nZW5lX21vZDwtcmVhZFJEUygiL2RhdGEvc2hhcmUvaHRwL3ByaW1lLXNlcV9QYXBlci9nZW5vbWVzL0hzYXAvZ2VuY29kZS52MzUucHJpbWFyeV9hc3NlbWJseS5hbm5vdGF0aW9uLmd0Zi5nZW5lbW9kZWxzX0dlbmV2aXoucmRzIikKCgphbm5vdC5jb2xvcnMgPC0gbGlzdCgiaW50cm9ucyI9IiNmZjUxNTQiLCJleG9ucyI9IiM5MWE2ZmYiKQoKCmJhbV9maWxlczwtIi9kYXRhL3NoYXJlL2h0cC9wcmltZS1zZXFfUGFwZXIvRmlnX2JlYWRzX2NvbHVtbnMvelVNSXMvSEVLL0J1bGtfb3B0X2x5c2lzX3Rlc3RfMl9IRUsuZmlsdGVyZWQuQWxpZ25lZC5HZW5lVGFnZ2VkLnNvcnRlZC5iYW0iCgppbmV4PC1yZXYoYygiaW50cm9ucyIsImV4b25zIikpCmIuaW5mIDwtZGF0YS5mcmFtZShiYW1maWxlPWMocGFzdGUoZ3N1Yih4ID0gYmFtX2ZpbGVzLHBhdHRlcm49Ii5iYW0iLHJlcGxhY2VtZW50ID0gIiIpLGluZXgsImJhbSIsc2VwPSIuIikpLGNvbmQxPWluZXgsY29uZDI9cmVwKCJIRUsiLHRpbWVzPTIpKQpnZW5lLm1vZGVsczwtIEdWX2dlbmVfbW9kICMgZ2VuZW1vZGVscyBmcm9tIG1ha2VHdml6X2dlbmVNb2RlbF9mcm9tX2dlbmNvZGUKZ2VuPSJoZzM4IiAjIGdlbm9tZQp0eXBlPSJSTkEiICMgc2VxdWVuY2luZyB0eXBlIFJOQS1zZXEgb3IgQVRBQy1zZXEKCgpmb3IgKGkgaW4gMToyMCl7CiMgcGxvdHRpbmcgcmFuZ2UgCiAgUFJhbmdlIDwtIGd0ZiAlPiUKICAgIGFzLnRpYmJsZSAlPiUgCiAgICBtdXRhdGUoRU5TRz1zdHJfc3BsaXRfZml4ZWQoZ2VuZV9pZCwKICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlsuXSIsCiAgICAgICAgICAgICAgICAgICAgbiA9IDIpWywgMV0pICU+JSAKICAgIGZpbHRlcihFTlNHICVpbiUgdG9wX2dlbmVzX2luZXgkRU5TRU1CTFtpXSkgJT4lIAogICAgZ3JvdXBfYnkoc2VxbmFtZXMsIHN0cmFuZCwgZ2VuZV9pZCkgJT4lCiAgICBzdW1tYXJpemUoc3RhcnQgPSBtaW4oc3RhcnQpLCBlbmQgPSBtYXgoZW5kKSkgJT4lCiAgICBwbHlyYW5nZXM6OmFzX2dyYW5nZXMoKQoKcHJpbnQodG9wX2dlbmVzX2luZXgkZXh0ZXJuYWxfZ2VuZV9uYW1lW2ldKQpwcmludCh0b3BfZ2VuZXNfaW5leCRjaHJvbW9zb21lX25hbWVbaV0pCnByaW50KGxlbmd0aChQUmFuZ2UpPjApCmlmKGxlbmd0aChQUmFuZ2UpPjApewoKZmlndXJlLm5hbWUxID0gcGFzdGUwKCJjb3ZlcmFnZVBsb3RzL0ludHJvbl9FeG9uX21hcHBpbmdfIix0b3BfZ2VuZXNfaW5leCRlbnNlbWJsX2dlbmVfaWRfdmVyc2lvbltpXSwiLnBkZiIpCgoKClBsb3RfQ292ZXJhZ2UoUFJhbmdlPVBSYW5nZSwKICAgICAgICAgICAgICBhbm5vdC5jb2xvcnM9YW5ub3QuY29sb3JzLAogICAgICAgICAgICAgIGIuaW5mPWIuaW5mLAogICAgICAgICAgICAgIGdlbmUubW9kZWxzPWdlbmUubW9kZWxzLAogICAgICAgICAgICAgIGZpZ3VyZS5uYW1lPWZpZ3VyZS5uYW1lMSwKICAgICAgICAgICAgICBnZW49Z2VuLAogICAgICAgICAgICAgIHR5cGU9dHlwZSwKICAgICAgICAgICAgICBwZGY9VCwKICAgICAgICAgICAgICB0aXRsZT10b3BfZ2VuZXNfaW5leCRleHRlcm5hbF9nZW5lX25hbWVbaV0sCiAgICAgICAgICAgICAgZXh0ZW5kLnJhbmdlPTJlNCwKICAgICAgICAgICAgICB5bWF4PShzdW0odG9wX2dlbmVzX21hdFt0b3BfZ2VuZXNfbWF0JHR5cGU9PSJFeG9uIix0b3BfZ2VuZXNfaW5leCRFTlNFTUJMW2ldXSkvNCkjIyBzZXQgeSBheGlzIGZvciBjb3ZlcmFnZSBwbG90IHRvIHN1bSBvZiBleG9uIGNvdW50cwogICAgICAgICAgICAgICkKCgp9Cn0KCgoKZm9yIChpIGluIDE6MjApewoKZmlndXJlLm5hbWUyID0gcGFzdGUwKCJjb3ZlcmFnZVBsb3RzL0ludHJvbl9FeG9uX2V4cHJlc3Npb25fIix0b3BfZ2VuZXNfaW5leCRlbnNlbWJsX2dlbmVfaWRfdmVyc2lvbltpXSwiLnBkZiIpCnAuZXhwPC10b3BfZ2VuZXNfbWF0ICU+JSAKICBkcGx5cjo6c2VsZWN0KGModHlwZSx0b3BfZ2VuZXNfaW5leCRFTlNFTUJMW2ldKSkgJT4lIAogIHJlbmFtZSgiRW5zZW1ibCI9dG9wX2dlbmVzX2luZXgkRU5TRU1CTFtpXSkgJT4lIAogIGZpbHRlcih0eXBlIT0iQm90aCIpJT4lIAogIGdncGxvdChhZXMoeT1FbnNlbWJsLHg9dHlwZSxjb2w9dHlwZSkpKwogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEYpKwogIGdnYmVlc3dhcm06Omdlb21fYmVlc3dhcm0oYWVzKGNvbD10eXBlKSxzaG93LmxlZ2VuZCA9IEYpKwogIGZhY2V0X3dyYXAofnR5cGUsc2NhbGU9ImZyZWVfeCIsbnJvdyA9IDIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD0gZWxlbWVudF9ibGFuaygpKSsKICBsYWJzKHg9IiIseT1wYXN0ZTAoIlVNSXMgKCIsdG9wX2dlbmVzX2luZXgkZXh0ZXJuYWxfZ2VuZV9uYW1lW2ldLCIpIikpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9aW5leF9jb2xvcnMsbGltaXRzPWZvcmNlKSAKCmdnc2F2ZShwbG90ID0gcC5leHAsZGV2aWNlID0gInBkZiIsZmlsZW5hbWUgPSBmaWd1cmUubmFtZTIsd2lkdGg9MixoZWlnaHQ9NCxzY2FsZT0xLjUpCn0KCmBgYAoKIyMgRXhwb3J0IHBsb3QgZm9yIEVOQUgKCmBgYHtyfQoKaT04CiBQUmFuZ2UgPC0gZ3RmICU+JQogICAgYXMudGliYmxlICU+JSAKICAgIG11dGF0ZShFTlNHPXN0cl9zcGxpdF9maXhlZChnZW5lX2lkLAogICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiWy5dIiwKICAgICAgICAgICAgICAgICAgICBuID0gMilbLCAxXSkgJT4lIAogICAgZmlsdGVyKEVOU0cgJWluJSB0b3BfZ2VuZXNfaW5leCRFTlNFTUJMW2ldKSAlPiUgCiAgICBncm91cF9ieShzZXFuYW1lcywgc3RyYW5kLCBnZW5lX2lkKSAlPiUKICAgIHN1bW1hcml6ZShzdGFydCA9IG1pbihzdGFydCksIGVuZCA9IG1heChlbmQpKSAlPiUKICAgIHBseXJhbmdlczo6YXNfZ3JhbmdlcygpCgogCmZpZ3VyZS5uYW1lMSA9IHBhc3RlMCgiY292ZXJhZ2VQbG90cy9JbnRyb25fRXhvbl9tYXBwaW5nXyIsdG9wX2dlbmVzX2luZXgkZW5zZW1ibF9nZW5lX2lkX3ZlcnNpb25baV0sIi5wZGYiKQogClBsb3RfQ292ZXJhZ2UoUFJhbmdlPVBSYW5nZSwKICAgICAgICAgICAgICBhbm5vdC5jb2xvcnM9YW5ub3QuY29sb3JzLAogICAgICAgICAgICAgIGIuaW5mPWIuaW5mLAogICAgICAgICAgICAgIGdlbmUubW9kZWxzPWdlbmUubW9kZWxzLAogICAgICAgICAgICAgIGZpZ3VyZS5uYW1lPWZpZ3VyZS5uYW1lMSwKICAgICAgICAgICAgICBnZW49Z2VuLAogICAgICAgICAgICAgIHR5cGU9dHlwZSwKICAgICAgICAgICAgICBwZGY9VCwKICAgICAgICAgICAgICB0aXRsZT10b3BfZ2VuZXNfaW5leCRleHRlcm5hbF9nZW5lX25hbWVbaV0sCiAgICAgICAgICAgICAgZXh0ZW5kLnJhbmdlPTJlNCwKICAgICAgICAgICAgICB5bWF4PTQwMAogICAgICAgICAgICAgICkKCmBgYAoKYGBge3J9CgoKaW50cm9uX29ubHlfZ2VuZWluZm88LXVwc2V0X2RmW3doaWNoKHVwc2V0X2RmJEVOU0VNQkwlaW4laW50cm9uX29ubHlfZ2VuZXMpLF0gJT4lIAogIGZpbHRlcighZHVwbGljYXRlZChFTlNFTUJMKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiRU5TRU1CTCIpCgoKZm9yIChpIGluIGludHJvbl9vbmx5X2dlbmVzWzE6MjBdKXsKICAKIFBSYW5nZSA8LSBndGYgJT4lCiAgICBhcy50aWJibGUgJT4lIAogICAgbXV0YXRlKEVOU0c9c3RyX3NwbGl0X2ZpeGVkKGdlbmVfaWQsCiAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJbLl0iLAogICAgICAgICAgICAgICAgICAgIG4gPSAyKVssIDFdKSAlPiUgCiAgICBmaWx0ZXIoRU5TRyAlaW4lIGkpICU+JSAKICAgIGdyb3VwX2J5KHNlcW5hbWVzLCBzdHJhbmQsIGdlbmVfaWQpICU+JQogICAgc3VtbWFyaXplKHN0YXJ0ID0gbWluKHN0YXJ0KSwgZW5kID0gbWF4KGVuZCkpICU+JQogICAgcGx5cmFuZ2VzOjphc19ncmFuZ2VzKCkKcHJpbnQod2lkdGgoUFJhbmdlKSkKIApmaWd1cmUubmFtZTEgPSBwYXN0ZTAoImNvdmVyYWdlUGxvdHMvSW50cm9uX29ubHlfbWFwcGluZ18iLGksIi5wZGYiKQogClBsb3RfQ292ZXJhZ2UoUFJhbmdlPVBSYW5nZSwKICAgICAgICAgICAgICBhbm5vdC5jb2xvcnM9YW5ub3QuY29sb3JzLAogICAgICAgICAgICAgIGIuaW5mPWIuaW5mLAogICAgICAgICAgICAgIGdlbmUubW9kZWxzPWdlbmUubW9kZWxzLAogICAgICAgICAgICAgIGZpZ3VyZS5uYW1lPWZpZ3VyZS5uYW1lMSwKICAgICAgICAgICAgICBnZW49Z2VuLAogICAgICAgICAgICAgIHR5cGU9dHlwZSwKICAgICAgICAgICAgICBwZGY9VCwKICAgICAgICAgICAgICB0aXRsZT1pbnRyb25fb25seV9nZW5laW5mb1tpLCJleHRlcm5hbF9nZW5lX25hbWUiXSwKICAgICAgICAgICAgICBleHRlbmQucmFuZ2U9d2lkdGgoUFJhbmdlKSowLjUsCiAgICAgICAgICAgICAgeW1heD04MDAKICAgICAgICAgICAgICApCn0KCmBgYAoK