Calculating error rates.
I wrote the function ‘create_matrices()’ to collect mutation counts. At least in theory the results from it should be able to address most/any question regarding the counts of mutations observed in the data.
## Loading errRt
## Loading required package: dplyr
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:hpgltools':
##
## combine
## The following object is masked from 'package:Biobase':
##
## combine
## The following objects are masked from 'package:BiocGenerics':
##
## combine, intersect, setdiff, union
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Loading required package: tidyr
## Starting sample: 1.
## Reading the file containing mutations: preprocessing/s1/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s1/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 1156535 reads.
## After position pruning, there are: 1037310 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1037310 reads.
## After N pruning, there are: 1021066 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 1742743 indexes.
## After read pruning, there are: 838158 indexes.
## Removing indexes with fewer than 3 indexes.
## Before index pruning, there are: 1021066 changed reads.
## Before index pruning, there are: 4681501 identical reads.
## After index pruning, there are: 532571 changed reads.
## After index pruning, there are: 3663814 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 3 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Starting sample: 2.
## Reading the file containing mutations: preprocessing/s2/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s2/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 3421203 reads.
## After position pruning, there are: 1758479 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1758479 reads.
## After N pruning, there are: 1732605 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 1263563 indexes.
## After read pruning, there are: 694479 indexes.
## Removing indexes with fewer than 3 indexes.
## Before index pruning, there are: 1732605 changed reads.
## Before index pruning, there are: 5230976 identical reads.
## After index pruning, there are: 874781 changed reads.
## After index pruning, there are: 4834367 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 3 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Starting sample: 3.
## Reading the file containing mutations: preprocessing/s3/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s3/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 4309681 reads.
## After position pruning, there are: 1564155 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1564155 reads.
## After N pruning, there are: 1532016 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 887982 indexes.
## After read pruning, there are: 465046 indexes.
## Removing indexes with fewer than 3 indexes.
## Before index pruning, there are: 1532016 changed reads.
## Before index pruning, there are: 3583390 identical reads.
## After index pruning, there are: 783358 changed reads.
## After index pruning, there are: 3332425 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 3 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Working on miss_reads_by_position.
## Working on miss_indexes_by_position.
## Working on miss_sequencer_by_position.
## Working on miss_reads_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_indexes_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_sequencer_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_reads_by_ref_nt.
## Working on miss_indexes_by_ref_nt.
## Working on miss_sequencer_by_ref_nt.
## Working on miss_reads_by_hit_nt.
## Working on miss_indexes_by_hit_nt.
## Working on miss_sequencer_by_hit_nt.
## Working on miss_reads_by_type.
## Working on miss_indexes_by_type.
## Working on miss_sequencer_by_type.
## Working on miss_reads_by_trans.
## Working on miss_indexes_by_trans.
## Working on miss_sequencer_by_trans.
## Working on miss_reads_by_strength.
## Working on miss_indexes_by_strength.
## Working on miss_sequencer_by_strength.
## Working on insert_reads_by_position.
## Working on insert_indexes_by_position.
## Working on insert_sequencer_by_position.
## Working on insert_reads_by_nt.
## Working on insert_indexes_by_nt.
## Working on insert_sequencer_by_nt.
## Working on delete_reads_by_position.
## Working on delete_indexes_by_position.
## Working on delete_sequencer_by_position.
## Working on delete_reads_by_nt.
## Working on delete_indexes_by_nt.
## Working on delete_sequencer_by_nt.
## Skipping table: delete_reads_by_position
## Skipping table: delete_indexes_by_position
## Skipping table: delete_sequencer_by_position
## Skipping table: delete_reads_by_nt
## Skipping table: delete_indexes_by_nt
## Skipping table: delete_sequencer_by_nt
## Length Class Mode
## samples 3 -none- list
## reads_per_sample 3 -none- numeric
## indexes_per_sample 3 -none- numeric
## matrices 33 -none- list
## matrices_by_counts 33 -none- list
## normalized 33 -none- list
## normalized_by_counts 33 -none- list
## Starting sample: 1.
## Reading the file containing mutations: preprocessing/s1/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s1/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 1156535 reads.
## After position pruning, there are: 1037310 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1037310 reads.
## After N pruning, there are: 1021066 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 1742743 indexes.
## After read pruning, there are: 838158 indexes.
## Removing indexes with fewer than 5 indexes.
## Before index pruning, there are: 1021066 changed reads.
## Before index pruning, there are: 4681501 identical reads.
## After index pruning, there are: 532571 changed reads.
## After index pruning, there are: 3663814 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 5 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Starting sample: 2.
## Reading the file containing mutations: preprocessing/s2/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s2/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 3421203 reads.
## After position pruning, there are: 1758479 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1758479 reads.
## After N pruning, there are: 1732605 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 1263563 indexes.
## After read pruning, there are: 694479 indexes.
## Removing indexes with fewer than 5 indexes.
## Before index pruning, there are: 1732605 changed reads.
## Before index pruning, there are: 5230976 identical reads.
## After index pruning, there are: 874781 changed reads.
## After index pruning, there are: 4834367 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 5 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Starting sample: 3.
## Reading the file containing mutations: preprocessing/s3/step4.txt.xz
## Reading the file containing the identical reads: preprocessing/s3/step2_identical_reads.txt.xz
## Removing any differences before position: 24.
## Before pruning, there are: 4309681 reads.
## After position pruning, there are: 1564155 reads.
## Removing any reads with 'N' as the hit.
## Before N pruning, there are: 1564155 reads.
## After N pruning, there are: 1532016 reads.
## Gathering information about the indexes observed, this is slow.
## Before read pruning, there are: 887982 indexes.
## After read pruning, there are: 465046 indexes.
## Removing indexes with fewer than 5 indexes.
## Before index pruning, there are: 1532016 changed reads.
## Before index pruning, there are: 3583390 identical reads.
## After index pruning, there are: 783358 changed reads.
## After index pruning, there are: 3332425 identical reads.
## Gathering identical, mutant, and sequencer reads/indexes.
## Counting by direction.
## Counting by string.
## Subsetting based on mutations with at least 5 indexes.
## Counting by reference position.
## Counting by identity string.
## Counting by reference nucleotide.
## Counting by product nucleotide.
## Counting by mutation type.
## Counting by transitions/transversion.
## Counting strong/weak.
## Counting insertions by position.
## Counting insertions by nucleotide
## Counting deletions by position.
## Counting deletions by nucleotide.
## Working on miss_reads_by_position.
## Working on miss_indexes_by_position.
## Working on miss_sequencer_by_position.
## Working on miss_reads_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_indexes_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_sequencer_by_string.
## Warning in order(as.numeric(rownames(matrices[[t]]))): NAs introduced by
## coercion
## Working on miss_reads_by_ref_nt.
## Working on miss_indexes_by_ref_nt.
## Working on miss_sequencer_by_ref_nt.
## Working on miss_reads_by_hit_nt.
## Working on miss_indexes_by_hit_nt.
## Working on miss_sequencer_by_hit_nt.
## Working on miss_reads_by_type.
## Working on miss_indexes_by_type.
## Working on miss_sequencer_by_type.
## Working on miss_reads_by_trans.
## Working on miss_indexes_by_trans.
## Working on miss_sequencer_by_trans.
## Working on miss_reads_by_strength.
## Working on miss_indexes_by_strength.
## Working on miss_sequencer_by_strength.
## Working on insert_reads_by_position.
## Working on insert_indexes_by_position.
## Working on insert_sequencer_by_position.
## Working on insert_reads_by_nt.
## Working on insert_indexes_by_nt.
## Working on insert_sequencer_by_nt.
## Working on delete_reads_by_position.
## Working on delete_indexes_by_position.
## Working on delete_sequencer_by_position.
## Working on delete_reads_by_nt.
## Working on delete_indexes_by_nt.
## Working on delete_sequencer_by_nt.
## Skipping table: delete_reads_by_position
## Skipping table: delete_indexes_by_position
## Skipping table: delete_sequencer_by_position
## Skipping table: delete_reads_by_nt
## Skipping table: delete_indexes_by_nt
## Skipping table: delete_sequencer_by_nt
## Length Class Mode
## samples 3 -none- list
## reads_per_sample 3 -none- numeric
## indexes_per_sample 3 -none- numeric
## matrices 33 -none- list
## matrices_by_counts 33 -none- list
## normalized 33 -none- list
## normalized_by_counts 33 -none- list
Print normalized plots
## Normalized table: delete_sequencer_by_nt.
## Error in print(data_plots[["normal"]][t]): object 'data_plots' not found
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
locale: LC_CTYPE=en_US.UTF-8, LC_NUMERIC=C, LC_TIME=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C
attached base packages: parallel, stats, graphics, grDevices, utils, datasets, methods and base
other attached packages: errRt(v.1.0), tidyr(v.1.0.0), dplyr(v.0.8.3), hpgltools(v.1.0), Biobase(v.2.46.0) and BiocGenerics(v.0.32.0)
loaded via a namespace (and not attached): tidyselect(v.0.2.5), lme4(v.1.1-21), RSQLite(v.2.1.4), AnnotationDbi(v.1.48.0), grid(v.3.6.1), BiocParallel(v.1.20.0), devtools(v.2.2.1), munsell(v.0.5.0), codetools(v.0.2-16), withr(v.2.1.2), colorspace(v.1.4-1), GOSemSim(v.2.12.0), highr(v.0.8), knitr(v.1.26), rstudioapi(v.0.10), stats4(v.3.6.1), DOSE(v.3.12.0), labeling(v.0.3), urltools(v.1.7.3), GenomeInfoDbData(v.1.2.2), polyclip(v.1.10-0), bit64(v.0.9-7), farver(v.2.0.1), rprojroot(v.1.3-2), vctrs(v.0.2.1), xfun(v.0.11), BiocFileCache(v.1.10.2), R6(v.2.4.1), doParallel(v.1.0.15), GenomeInfoDb(v.1.22.0), graphlayouts(v.0.5.0), locfit(v.1.5-9.1), bitops(v.1.0-6), fgsea(v.1.12.0), gridGraphics(v.0.4-1), DelayedArray(v.0.12.0), assertthat(v.0.2.1), scales(v.1.1.0), ggraph(v.2.0.0), enrichplot(v.1.6.0), gtable(v.0.3.0), sva(v.3.34.0), processx(v.3.4.1), tidygraph(v.1.1.2), rlang(v.0.4.2), zeallot(v.0.1.0), genefilter(v.1.68.0), splines(v.3.6.1), rtracklayer(v.1.46.0), lazyeval(v.0.2.2), europepmc(v.0.3), BiocManager(v.1.30.10), yaml(v.2.2.0), reshape2(v.1.4.3), GenomicFeatures(v.1.38.0), backports(v.1.1.5), qvalue(v.2.18.0), clusterProfiler(v.3.14.0), tools(v.3.6.1), usethis(v.1.5.1), ggplotify(v.0.0.4), ggplot2(v.3.2.1), ellipsis(v.0.3.0), gplots(v.3.0.1.1), RColorBrewer(v.1.1-2), sessioninfo(v.1.1.1), ggridges(v.0.5.1), Rcpp(v.1.0.3), plyr(v.1.8.5), base64enc(v.0.1-3), progress(v.1.2.2), zlibbioc(v.1.32.0), purrr(v.0.3.3), RCurl(v.1.95-4.12), ps(v.1.3.0), prettyunits(v.1.0.2), openssl(v.1.4.1), viridis(v.0.5.1), cowplot(v.1.0.0), S4Vectors(v.0.24.1), SummarizedExperiment(v.1.16.0), ggrepel(v.0.8.1), colorRamps(v.2.3), fs(v.1.3.1), variancePartition(v.1.16.0), magrittr(v.1.5), data.table(v.1.12.8), DO.db(v.2.9), openxlsx(v.4.1.4), triebeard(v.0.3.0), matrixStats(v.0.55.0), pkgload(v.1.0.2), hms(v.0.5.2), evaluate(v.0.14), xtable(v.1.8-4), pbkrtest(v.0.4-7), XML(v.3.98-1.20), IRanges(v.2.20.1), gridExtra(v.2.3), testthat(v.2.3.1), compiler(v.3.6.1), biomaRt(v.2.42.0), tibble(v.2.1.3), KernSmooth(v.2.23-16), crayon(v.1.3.4), minqa(v.1.2.4), htmltools(v.0.4.0), mgcv(v.1.8-31), DBI(v.1.0.0), tweenr(v.1.0.1), dbplyr(v.1.4.2), MASS(v.7.3-51.4), rappdirs(v.0.3.1), boot(v.1.3-23), Matrix(v.1.2-18), readr(v.1.3.1), cli(v.2.0.0), gdata(v.2.18.0), igraph(v.1.2.4.2), GenomicRanges(v.1.38.0), pkgconfig(v.2.0.3), rvcheck(v.0.1.7), GenomicAlignments(v.1.22.1), xml2(v.1.2.2), foreach(v.1.4.7), annotate(v.1.64.0), XVector(v.0.26.0), stringr(v.1.4.0), callr(v.3.4.0), digest(v.0.6.23), Biostrings(v.2.54.0), rmarkdown(v.1.18), fastmatch(v.1.1-0), edgeR(v.3.28.0), curl(v.4.3), Rsamtools(v.2.2.1), gtools(v.3.8.1), nloptr(v.1.2.1), lifecycle(v.0.1.0), nlme(v.3.1-143), jsonlite(v.1.6), desc(v.1.2.0), viridisLite(v.0.3.0), askpass(v.1.1), limma(v.3.42.0), fansi(v.0.4.0), pillar(v.1.4.3), lattice(v.0.20-38), httr(v.1.4.1), pkgbuild(v.1.0.6), survival(v.3.1-8), GO.db(v.3.10.0), glue(v.1.3.1), remotes(v.2.1.0), zip(v.2.0.4), iterators(v.1.0.12), pander(v.0.6.3), bit(v.1.1-14), ggforce(v.0.3.1), stringi(v.1.4.3), blob(v.1.2.0), caTools(v.1.17.1.3) and memoise(v.1.1.0)
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset defea68c4df789830e6d759243e1f973d2d9dca7
## This is hpgltools commit: Fri Dec 27 17:07:39 2019 -0500: defea68c4df789830e6d759243e1f973d2d9dca7
## Error in gsub(pattern = "\\.Rmd", replace = "", x = rmd_file): object 'rmd_file' not found
## Error in paste0("Saving to ", this_save): object 'this_save' not found
## Error in file.path(getwd(), directory, filename): object 'this_save' not found
LS0tCnRpdGxlOiAiQ291bnRpbmcgUlQgbXV0YXRpb25zIGZyb20gaWxsdW1pbmEgc2VxdWVuY2luZyBkYXRhLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoImhwZ2x0b29scyIpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgiL2RhdGEvaHBnbHRvb2xzIikKa25pdHI6Om9wdHNfa25pdCRzZXQod2lkdGg9MTIwLAogICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBkcGk9OTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdD0iJVklbSVkIikKcHJldmlvdXNfZmlsZSA8LSAiaW5kZXguUm1kIgp2ZXIgPC0gIjIwMTkxMjAxIgoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCiMjcm1kX2ZpbGUgPC0gIjAzX2V4cHJlc3Npb25faW5mZWN0aW9uXzIwMTgwODIyLlJtZCIKYGBgCgojIENhbGN1bGF0aW5nIGVycm9yIHJhdGVzLgoKSSB3cm90ZSB0aGUgZnVuY3Rpb24gJ2NyZWF0ZV9tYXRyaWNlcygpJyB0byBjb2xsZWN0IG11dGF0aW9uIGNvdW50cy4gIEF0IGxlYXN0CmluIHRoZW9yeSB0aGUgcmVzdWx0cyBmcm9tIGl0IHNob3VsZCBiZSBhYmxlIHRvIGFkZHJlc3MgbW9zdC9hbnkgcXVlc3Rpb24KcmVnYXJkaW5nIHRoZSBjb3VudHMgb2YgbXV0YXRpb25zIG9ic2VydmVkIGluIHRoZSBkYXRhLgoKYGBge3IgdGVzdGluZ30KZGV2dG9vbHM6OmxvYWRfYWxsKCJlcnJSdCIpCgp0cmlwbGV0cyA8LSBjcmVhdGVfbWF0cmljZXMoc2FtcGxlX3NoZWV0PSJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnRfY29sdW1uPSJpZGVudHRhYmxlIiwgbXV0X2NvbHVtbj0ibXV0YXRpb250YWJsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fcmVhZHM9MywgbWluX2luZGV4ZXM9MywgbWluX3NlcXVlbmNlcj0xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl9wb3NpdGlvbj0yNCwgcHJ1bmVfbj1UUlVFLCB2ZXJib3NlPVRSVUUpCnRyaXBsZXRfcGxvdHMgPC0gYmFycGxvdF9tYXRyaWNlcyh0cmlwbGV0cykKc3VtbWFyeSh0cmlwbGV0cykKcXVpbnR1cGxldHMgPC0gY3JlYXRlX21hdHJpY2VzKHNhbXBsZV9zaGVldD0ic2FtcGxlX3NoZWV0cy9hbGxfc2FtcGxlcy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50X2NvbHVtbj0iaWRlbnR0YWJsZSIsIG11dF9jb2x1bW49Im11dGF0aW9udGFibGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX3JlYWRzPTMsIG1pbl9pbmRleGVzPTUsIG1pbl9zZXF1ZW5jZXI9MTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fcG9zaXRpb249MjQsIHBydW5lX249VFJVRSwgdmVyYm9zZT1UUlVFKQpxdWludHVwbGV0X3Bsb3RzIDwtIGJhcnBsb3RfbWF0cmljZXMocXVpbnR1cGxldHMpCnN1bW1hcnkodHJpcGxldHMpCmBgYAoKIyBRdWVzdGlvbnMgZnJvbSBEci4gRGVTdGVmYW5vCgpJIHRoaW5rIHdoYXQgaXMgYmVzdCBpcyB0byBnZXQgdGhlIG51bWJlciBvZiByZWNvdmVyZWQgbXV0YXRpb25zIG9mIGVhY2ggdHlwZQpmcm9tIGVhY2ggZGF0YSBzZXQuICBUaGF0IHdvdWxkIGJlIEEgdG8gVCwgQSB0byBHLCBBIHRvIEM7IFQgdG8gQSwgVCB0byBHLCBUIHRvCkM7IEcgdG8gQSwgRyB0byBDLCBHIHRvIFQ7IGFuZCBDIHRvIEEsIEMgdG8gRywgQyB0byBUOyBhcyB3ZWxsIGFzIGRlbGV0aW9ucyBhbmQKaW5zZXJ0aW9ucy4gIEkgd291bGQgdGhlbiBuZWVkIHRoZSBzdW0gbnVtYmVyIG9mIHRoZSByZWFkcyB0aGF0IG1ldCBhbGwgb3VyCmNyaXRlcmlhIChpLmUuIGF0IGxlYXN0IDMgZ29vZCByZWNvdmVyZWQgcmVhZHMgZm9yIHRoYXQgMTQgbnQgaW5kZXgpLiAgRWFjaCBzZXQKb2YgMyBvciBtb3JlIHdvdWxkIGN0IGFzICIxIiByZWFkIG9mIHRoYXQgcGFydGljdWxhciBpbmRleCBzbyBJIHdvdWxkIG5lZWQgdGhlCnRvdGFsIHdpdGggdGhpcyBpbiBtaW5kLiAgSSBhbHNvIG5lZWQgdG8ga25vdyB0aGUgdG90YWwgbnVtYmVyIG9mIG51Y2xlb3RpZGVzCnRoYXQgd2VyZSBpbiB0aGUgcmVnaW9uIHdlIGRlY2lkZWQgdG8gY29uc2lkZXIgaW4gdGhlIGFuYWx5c2lzLiAgV2UgbWF5IHdhbnQgdG8KdHJ5IHRoaXMgZm9yIDMgb3IgbW9yZSBhbmQgNSBvciBtb3JlIHJlY292ZXJlZCBpbmRleGVzIGlmIGl0IGlzIG5vdCBoYXJkLiAgVGhpcwppbmZvcm1hdGlvbiBkb2VzIG5vdCBpbmNsdWRlIHNwZWNpZmljIHBvc2l0aW9ucyBvbiB0aGUgdGVtcGxhdGUgd2hlcmUgZXJyb3JzCm9jY3VycmVkIGJ1dCB3ZSBjYW4gbG9vayBhdCB0aGF0IGxhdHRlci4gIFJpZ2h0IG5vdyBJIGp1c3Qgd2FudCB0byBnZXQgYSBnZW5lcmFsCmVycm9yIHJhdGUgYW5kIHR5cGUgb2YgZXJyb3IuICBJdCB3b3VsZCBiYXNpY2FsbHkgYmUgY2FsY3VsYXRlZCBieSBkaXZpZGluZyB0aGUKbnVtYmVyIG9mIHJlY292ZXJlZCBtdXRhdGlvbnMgb2YgYSBwYXJ0aWN1bGFyIHR5cGUgYnkgc3VtIG51bWJlciBvZiB0aGUgcmVhZHMKdGltZXMgdGhlIG51bWJlciBvZiBudWNsZW90aWRlcyBzY3JlZW5lZCBpbiB0aGUgdGVtcGxhdGUuICBBcyBpdCBlbmRzIHVwLCB0aGlzCm51bWJlciBkb2VzIG5vdCByZWFsbHkgaGF2ZSBhIGxvdCBvZiBtZWFuaW5nIGJ1dCBpdCBjYW4gYmUgdXNlZCB0byBjYWxjdWxhdGUgdGhlCm92ZXJhbGwgbXV0YXRpb24gcmF0ZSBhcyB3ZWxsIGFzIHRoZSByYXRlIGZvciB0cmFuc3ZlcnNpb25zLCB0cmFuc2l0aW9ucywgYW5kCmRlbGV0aW9ucyBhbmQgaW5zZXJ0aW9ucy4KCiMgQW5zd2VycwoKSW4gb3JkZXIgdG8gYWRkcmVzcyB0aG9zZSBxdWVyaWVzLCBJIGludm9rZWQgY3JlYXRlX21hdHJpY2VzKCkgd2l0aCBhIG1pbmltdW0KaW5kZXggY291bnQgb2YgMyBhbmQgNS4gIEl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoaXMgaXMgbm90IHRoZSBzYW1lIGFzCnJlcXVpcmluZyAzIG9yIDUgcmVhZHMgcGVyIGluZGV4LiAgSW4gYm90aCBjYXNlcyBJIHJlcXVpcmUgMyByZWFkcyBwZXIgaW5kZXguCgojIyBSZWNvdmVyZWQgbXV0YXRpb25zIG9mIGVhY2ggdHlwZQoKSSBhbSBpbnRlcnByZXRpbmcgdGhpcyBxdWVzdGlvbiBhcyB0aGUgbnVtYmVyIG9mIGluZGV4ZXMgcmVjb3ZlcmVkIGZvciBlYWNoCm11dGF0aW9uIHR5cGUuICBJIGNvbGxlY3QgdGhpcyBpbmZvcm1hdGlvbiBpbiAyIHdheXMgb2YgaW50ZXJlc3Q6IHRoZSBpbmRleGVzIGJ5CnR5cGUgd2hpY2ggYXJlIGRlZW1lZCB0byBiZSBmcm9tIHRoZSBSVCBhbmQgZnJvbSB0aGUgc2VxdWVuY2VyLiAgSW4gYWRkaXRpb24sIEkKY2FsY3VsYXRlIGEgbm9ybWFsaXplZCAoY3BtKSB2ZXJzaW9uIG9mIHRoaXMgaW5mb3JtYXRpb24gd2hpY2ggbWF5IGJlIHVzZWQgdG8gbG9vayBmb3IKY2hhbmdlcyBhY3Jvc3Mgc2FtcGxlcy4KCiMjIyBNdXRhdGlvbnMgYnkgUlQgaW5kZXgKClRoaXMgZm9sbG93aW5nIGJsb2NrIHNob3VsZCBwcmludCBvdXQgdGFibGVzIG9mIHRoZSBudW1iZXJzIG9mIG11dGFudCBpbmRleGVzCm9ic2VydmVkIGZvciBlYWNoIHR5cGUgZm9yIHRoZSBSVCBhbmQgdGhlIHNlcXVlbmNlci4gIE9uZSB3b3VsZCBob3BlIHRoYXQgdGhlCnNlcXVlbmNlciB3aWxsIGJlIGNvbnNpc3RlbnQgZm9yIGFsbCBzYW1wbGVzLCBidXQgSSB0aGluayB0aGUgcmVzdWx0cyB3aWxsCmluc3RlYWQgc3VnZ2VzdCB0aGF0IG15IG1ldHJpYyBpcyBub3QgeWV0IHN0cmluZ2VudCBlbm91Z2guCgpgYGB7ciBtdXRhdGlvbl9pbmRleF9jb3VudCwgcmVzdWx0cz0nYXNpcyd9CmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm1hdHJpY2VzIl1dW1sibWlzc19pbmRleGVzX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUodHJpcGxldHNbWyJtYXRyaWNlcyJdXVtbIm1pc3Nfc2VxdWVuY2VyX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUocXVpbnR1cGxldHNbWyJtYXRyaWNlcyJdXVtbIm1pc3NfaW5kZXhlc19ieV90eXBlIl1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibWF0cmljZXMiXV1bWyJtaXNzX3NlcXVlbmNlcl9ieV90eXBlIl1dKQpgYGAKClBsb3RzIG9mIHRoaXMgaW5mb3JtYXRpb24KCmBgYHtyIG11dGF0aW9uX2luZGV4X2NvdW50X3Bsb3RzfQp0cmlwbGV0X3Bsb3RzW1sibWF0cmljZXMiXV1bWyJtaXNzX2luZGV4ZXNfYnlfdHlwZSJdXQp0cmlwbGV0X3Bsb3RzW1sibm9ybWFsIl1dW1sibWlzc19pbmRleGVzX2J5X3R5cGUiXV0KCnF1aW50dXBsZXRfcGxvdHNbWyJtYXRyaWNlcyJdXVtbIm1pc3NfaW5kZXhlc19ieV90eXBlIl1dCnF1aW50dXBsZXRfcGxvdHNbWyJub3JtYWwiXV1bWyJtaXNzX2luZGV4ZXNfYnlfdHlwZSJdXQpgYGAKClRoaXMgc3VnZ2VzdHMgdG8gbWUgdGhhdCB0aGlzIGluZm9ybWF0aW9uIG5lZWRzIHRvIGJlIG5vcm1hbGl6ZWQgaW4gc29tZSBtb3JlCnNlbnNpYmxlIGZhc2hpb24uICBUaHVzIHRoZSBmb2xsb3dpbmc6CgojIyMgTXV0YXRpb25zIGJ5IFJUIGluZGV4LCBwb3N0IG5vcm1hbGl6YXRpb24KClRoZSBzYW1lIG51bWJlcnMgbWF5IGJlIGV4cHJlc3NlZCBpbiB0aGUgY29udGV4dCBvZiB0aGUgbnVtYmVyIG9mIGluZGV4ZXMKb2JzZXJ2ZWQgLyBzYW1wbGUgYW5kL29yIGFzIGEgY3BtIGFjcm9zcyBzYW1wbGVzLiAgVGh1cyBpbiB0aGUgZmlyc3QgaW5zdGFuY2UKb25lIGNhbiBsb29rIGF0IHRoZSBhcHBhcmVudCBlcnJvciByYXRlIGZvciBlYWNoIHNhbXBsZSwgYW5kIGluIHRoZSBzZWNvbmQKaW5zdGFuY2Ugb25lIG1heSBsb29rIGZvciByZWxhdGl2ZSBjaGFuZ2VzIGluIGFwcGFyZW50IGVycm9yIHJhdGUgYWNyb3NzCnNhbXBsZXMuCgojIyMjIFJld3JpdGluZyB0aGUgbWF0cmljZXMgYXMgY3BtIHRvIGFjY291bnQgZm9yIGxpYnJhcnkgc2l6ZXMuCgpgYGB7ciBtdXRhdGlvbl9pbmRleF9ub3JtYWxpemVkLCByZXN1bHRzPSdhc2lzJ30Ka25pdHI6OmthYmxlKHRyaXBsZXRzW1sibm9ybWFsaXplZCJdXVtbIm1pc3NfaW5kZXhlc19ieV90eXBlIl1dKQoKa25pdHI6OmthYmxlKHRyaXBsZXRzW1sibm9ybWFsaXplZCJdXVtbIm1pc3Nfc2VxdWVuY2VyX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUocXVpbnR1cGxldHNbWyJub3JtYWxpemVkIl1dW1sibWlzc19pbmRleGVzX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUocXVpbnR1cGxldHNbWyJub3JtYWxpemVkIl1dW1sibWlzc19zZXF1ZW5jZXJfYnlfdHlwZSJdXSkKYGBgCgojIyMjIFJld3JpdGluZyB0aGUgbWF0cmljZXMgYnkgZGl2aWRpbmcgYnkgYWxsIGluZGV4ZXMKClRoaXMgSSB0aGluayBzdGFydHMgdG8gYWRkcmVzcyB0aGUgbGF0ZXIgdGV4dCBpbiB5b3VyIHF1ZXJ5LgoKYGBge3IgbXV0YXRpb25faW5kZXhfbm9ybWFsaXplZF9ieV9jb3VudHMsIHJlc3VsdHM9J2FzaXMnfQprbml0cjo6a2FibGUodHJpcGxldHNbWyJtYXRyaWNlc19ieV9jb3VudHMiXV1bWyJtaXNzX2luZGV4ZXNfYnlfdHlwZSJdXSkKCmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm1hdHJpY2VzX2J5X2NvdW50cyJdXVtbIm1pc3Nfc2VxdWVuY2VyX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUocXVpbnR1cGxldHNbWyJtYXRyaWNlc19ieV9jb3VudHMiXV1bWyJtaXNzX2luZGV4ZXNfYnlfdHlwZSJdXSkKCmtuaXRyOjprYWJsZShxdWludHVwbGV0c1tbIm1hdHJpY2VzX2J5X2NvdW50cyJdXVtbIm1pc3Nfc2VxdWVuY2VyX2J5X3R5cGUiXV0pCmBgYAoKIyMjIyBSZXdyaXRpbmcgdGhlIG1hdHJpY2VzIGJ5IGRpdmlkaW5nIGJ5IGFsbCBpbmRleGVzIGFuZCBjcG0KCkkgdGhpbmsgdGhpcyBtaWdodCBwcm92ZSB0byBiZSB3aGVyZSB3ZSBnZXQgdGhlIG1vc3QgbWVhbmluZ2Z1bCByZXN1bHRzLgoKVGhlIG5pY2VzdCB0aGluZyBpbiBpdCBpcyB0aGF0IGFmdGVyIGFjY291bnRpbmcgZm9yIGxpYnJhcnkgc2l6ZXMgYW5kIHRvdGFsCmluZGV4ZXMgb2JzZXJ2ZWQsIHdlIGZpbmFsbHkgc2VlIHRoYXQgdGhlIHNlcXVlbmNlciBlcnJvciBpcyBtb3N0bHkgY29uc2lzdGVudAphY3Jvc3MgYWxsIHNhbXBsZXMgYW5kIG11dGF0aW9uIHR5cGVzIC0tIHdpdGggYSBjb3VwbGUgb2Ygbm90YWJsZSBleGNlcHRpb25zLgoKQnkgdGhlIHNhbWUgdG9rZW4sIGZvciB0aGUgbXV0YXRpb25zIHdoaWNoIF9hcmVfIGlkZW50aWNhbCBmb3IgdGhlIHNlcXVlbmNlciwgd2UKaGF2ZSBzb21lIHdoaWNoIGFyZSBkZWNpZGVkbHkgZGlmZmVyZW50IGZvciB0aGUgbm9uLXNlcXVlbmNlciBkYXRhLiAgVGhlIG1vc3QKbm90YWJsZSBleGFtcGxlcyBJIHRoaW5rIGFyZSBBIHRvIEcgYnV0IF9ub3QgRyB0byBBOyBhbmQgQyB0byBULgoKYGBge3IgbXV0YXRpb25faW5kZXhfY3BtX2J5X2NvdW50cywgcmVzdWx0cz0nYXNpcyd9CmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm5vcm1hbGl6ZWRfYnlfY291bnRzIl1dW1sibWlzc19pbmRleGVzX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUodHJpcGxldHNbWyJub3JtYWxpemVkX2J5X2NvdW50cyJdXVtbIm1pc3Nfc2VxdWVuY2VyX2J5X3R5cGUiXV0pCgprbml0cjo6a2FibGUocXVpbnR1cGxldHNbWyJub3JtYWxpemVkX2J5X2NvdW50cyJdXVtbIm1pc3NfaW5kZXhlc19ieV90eXBlIl1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibm9ybWFsaXplZF9ieV9jb3VudHMiXV1bWyJtaXNzX3NlcXVlbmNlcl9ieV90eXBlIl1dKQpgYGAKCiMjIyBJbmRlbHMgYnkgUlQgaW5kZXgKClRoZSBmb2xsb3dpbmcgYmxvY2tzIHdpbGwgcmVwZWF0IHRoZSBhYm92ZSwgYnV0IGxvb2tpbmcgZm9yIGluc2VydGlvbnMuClRoaXMgZGF0YSBkb2VzIG5vdCBvYnNlcnZlIHN1ZmZpY2llbnQgZGVsZXRpb25zIHRvIG1ha2UgYSBwcm9wZXIgY291bnQgZm9yIHRoZW0uCgpgYGB7ciBpbnNlcnRfaW5kZXhfY291bnQsIHJlc3VsdHM9J2FzaXMnfQprbml0cjo6a2FibGUodHJpcGxldHNbWyJtYXRyaWNlcyJdXVtbImluc2VydF9pbmRleGVzX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHRyaXBsZXRzW1sibWF0cmljZXMiXV1bWyJpbnNlcnRfc2VxdWVuY2VyX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibWF0cmljZXMiXV1bWyJpbnNlcnRfaW5kZXhlc19ieV9udCJdXSkKCmtuaXRyOjprYWJsZShxdWludHVwbGV0c1tbIm1hdHJpY2VzIl1dW1siaW5zZXJ0X3NlcXVlbmNlcl9ieV9udCJdXSkKYGBgCgpQbG90cyBvZiB0aGlzIGluZm9ybWF0aW9uCgpgYGB7ciBpbnNlcnRfaW5kZXhfY291bnRfcGxvdHN9CnRyaXBsZXRfcGxvdHNbWyJtYXRyaWNlcyJdXVtbImluc2VydF9pbmRleGVzX2J5X250Il1dCnRyaXBsZXRfcGxvdHNbWyJub3JtYWwiXV1bWyJpbnNlcnRfaW5kZXhlc19ieV9udCJdXQoKcXVpbnR1cGxldF9wbG90c1tbIm1hdHJpY2VzIl1dW1siaW5zZXJ0X2luZGV4ZXNfYnlfbnQiXV0KcXVpbnR1cGxldF9wbG90c1tbIm1hdHJpY2VzIl1dW1siaW5zZXJ0X3NlcXVlbmNlcl9ieV9udCJdXQpxdWludHVwbGV0X3Bsb3RzW1sibm9ybWFsIl1dW1siaW5zZXJ0X2luZGV4ZXNfYnlfbnQiXV0KcXVpbnR1cGxldF9wbG90c1tbIm5vcm1hbCJdXVtbImluc2VydF9zZXF1ZW5jZXJfYnlfbnQiXV0KYGBgCgojIyMgSW5zZXJ0aW9ucyBieSBSVCBpbmRleCwgcG9zdCBub3JtYWxpemF0aW9uCgojIyMjIFJld3JpdGluZyB0aGUgbWF0cmljZXMgYXMgY3BtIHRvIGFjY291bnQgZm9yIGxpYnJhcnkgc2l6ZXMuCgpgYGB7ciBpbnNlcnRfaW5kZXhfbm9ybWFsaXplZCwgcmVzdWx0cz0nYXNpcyd9CmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm5vcm1hbGl6ZWQiXV1bWyJpbnNlcnRfaW5kZXhlc19ieV9udCJdXSkKCmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm5vcm1hbGl6ZWQiXV1bWyJpbnNlcnRfc2VxdWVuY2VyX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibm9ybWFsaXplZCJdXVtbImluc2VydF9pbmRleGVzX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibm9ybWFsaXplZCJdXVtbImluc2VydF9zZXF1ZW5jZXJfYnlfbnQiXV0pCmBgYAoKIyMjIyBSZXdyaXRpbmcgdGhlIG1hdHJpY2VzIGJ5IGRpdmlkaW5nIGJ5IGFsbCBpbmRleGVzCgpJIHRoaW5rIHRoYXQgdGhlcmUgYXJlIGZldyBlbm91Z2ggaW5zZXJ0aW9uIGV2ZW50cyB0aGF0IHRoaXMgZ2V0cyBhIGJpdCBtZXNzZWQKdXAuICBJIHdpbGwgZG91YmxlIGNoZWNrIHRoZSBsb2dpYyBvZiB0aGlzLCBidXQgdGhhdCBpcyBteSBpbml0aWFsIGd1ZXNzIGdpdmVuCmhvdyBmZXcgaW5zZXJ0aW9ucyBJIHdhcyBzZWVpbmcgd2hlbiByZWFkaW5nIHRoZSBvdXRwdXRzIG1hbnVhbGx5LgpVbmZvcnR1bmF0ZWx5LCB0aGlzIG1lYW5zIHRoYXQgZm9yIHRoZXNlIEkgYWxzbyBjYW5ub3QgcHJvdmlkZSBhIGNwbSBtZWFzdXJlbWVudC4KCmBgYHtyIGluc2VydF9pbmRleF9ub3JtYWxpemVkX2J5X2NvdW50cywgcmVzdWx0cz0nYXNpcyd9CmtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm1hdHJpY2VzX2J5X2NvdW50cyJdXVtbImluc2VydF9pbmRleGVzX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHRyaXBsZXRzW1sibWF0cmljZXNfYnlfY291bnRzIl1dW1siaW5zZXJ0X3NlcXVlbmNlcl9ieV9udCJdXSkKCmtuaXRyOjprYWJsZShxdWludHVwbGV0c1tbIm1hdHJpY2VzX2J5X2NvdW50cyJdXVtbImluc2VydF9pbmRleGVzX2J5X250Il1dKQoKa25pdHI6OmthYmxlKHF1aW50dXBsZXRzW1sibWF0cmljZXNfYnlfY291bnRzIl1dW1siaW5zZXJ0X3NlcXVlbmNlcl9ieV9udCJdXSkKYGBgCgpUaGUgZm9sbG93aW5nIGlzIG15IHByZXZpb3VzIHdyaXRpbmcgb2YgdGhpcyB3b3Jrc2hlZXQgd2hpY2gganVzdCBkdW1wZWQgdGhlCnZhcmlvdXMgdGFibGVzLgoKIyBQcmludCByYXcgdGFibGVzCgpgYGB7ciByYXcsIHJlc3VsdHM9J2FzaXMnfQpmb3IgKHQgaW4gMTpsZW5ndGgodHJpcGxldHNbWyJtYXRyaWNlcyJdXSkpIHsKICB0YWJsZV9uYW1lIDwtIG5hbWVzKHRyaXBsZXRzW1sibWF0cmljZXMiXV0pW3RdCiAgbWVzc2FnZSgiUmF3IHRhYmxlOiAiLCB0YWJsZV9uYW1lLCAiLiIpCiAgcHJpbnQoa25pdHI6OmthYmxlKHRyaXBsZXRzW1sibWF0cmljZXMiXV1bdF0pKQp9CmBgYAoKIyBQcmludCByYXcgcGxvdHMKCmBgYHtyIHJhd19wbG90c30KZm9yICh0IGluIDE6bGVuZ3RoKHRyaXBsZXRzW1sibWF0cmljZXMiXV0pKSB7CiAgbWVzc2FnZSgiUmF3IHRhYmxlOiAiLCB0YWJsZV9uYW1lLCAiLiIpCiAgcHJpbnQoZGF0YV9wbG90c1tbIm1hdHJpY2VzIl1dW3RdKQp9CmBgYAoKIyBQcmludCBub3JtYWxpemVkIHRhYmxlcwoKYGBge3Igbm9ybSwgcmVzdWx0cz0nYXNpcyd9CmZvciAodCBpbiAxOmxlbmd0aCh0cmlwbGV0c1tbIm5vcm1hbGl6ZWQiXV0pKSB7CiAgdGFibGVfbmFtZSA8LSBuYW1lcyh0cmlwbGV0c1tbIm5vcm1hbGl6ZWQiXV0pW3RdCiAgbWVzc2FnZSgiTm9ybWFsaXplZCB0YWJsZTogIiwgdGFibGVfbmFtZSwgIi4iKQogIHByaW50KGtuaXRyOjprYWJsZSh0cmlwbGV0c1tbIm5vcm1hbGl6ZWQiXV1bdF0pKQp9CmBgYAoKIyBQcmludCBub3JtYWxpemVkIHBsb3RzCgpgYGB7ciBub3JtX3Bsb3RzfQpmb3IgKHQgaW4gMTpsZW5ndGgodHJpcGxldHNbWyJub3JtYWxpemVkIl1dKSkgewogIG1lc3NhZ2UoIk5vcm1hbGl6ZWQgdGFibGU6ICIsIHRhYmxlX25hbWUsICIuIikKICBwcmludChkYXRhX3Bsb3RzW1sibm9ybWFsIl1dW3RdKQp9CmBgYAoKYGBge3Igc2F2ZW1lfQpwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQptZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKdGhpc19zYXZlIDwtIHBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cm1kX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikKbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCB0aGlzX3NhdmUpKQp0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCmBgYAoKCmBgYHtyIGxvYWRtZSwgZXZhbD1GQUxTRX0KbG9hZG1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkKYGBgCg==